![]("gganim.gif") needs to be fixed.

Motivation

Opioid prescription has become a popular topic because of the increasing prescription and concerns about overdose, opioid-related deaths, and other opioid-associated side effects. (Ref: Paulozzi et al. 2011, Rudd et al. 2016, Rudd et al. 2016, Solomon et al. 2010, Dunn, et al. 2010. )
Our motivation is to understand the opioid prescription in the States using publicly available data. Thus, the main questions we are going to ask include:

  1. Among the 50 States and District of Columbia, which five States had the highest and lowest number in

    1. Total opioid claims ,
    2. Opioid prescription rate ( = total opioid claims / total claims ) , and
    3. Opioid prescription per 100 enrollments ?
  2. Did the total number of opioid prescriptions change over time?

  3. Can you visualize the opioid prescription rate on the U.S map?

In this case study, we’ll walk you through collecting data, importing data, wrangling data, and visualizing the data, using the well-established and commonly used packages, including kableExtra, readr , tidyverse , datasets , ggplot2 , scales , ggrepel , choroplethr , and choroplethrMaps . Here we provide an overview aobut these packages before we starts:

R package What can the package provide?
kableExtra Helps with building complex tables and manipulating table styles; creates awesome HTML tables
readr Allows you to read data from various formats faster
tidyverse Provides user-friendly data manipulation
datasets Gives us useful information, including the States’ information
ggplot2 Improves data visualisations
scales Adds the flexibility of scaling
ggrepel Avoids superimposing the legends you don’t expect
choroplethr Helps preparing for plotting the U.S. Map
choroplethrMaps Helps us plot the U.S. Map

What is the data?

Recently, the Centers for Medicare & Medicaid Services (CMS) has prepared a public dataset, including information in the part D covering calendar years 2013 through 2016, to make our health care system more transparent, and to allow citizens to understand the medical expenditure and relevant health issues. You can find the description of the data here:
Medicare part D dataset

Medicare data (Part D)

Medicare Part D is prescription drug coverage plan run by Center for Medicare & Medicaid Services (CMS). Here is a website describing the information about Part D It was originally proposed by President Bill Clinton in 2000 based on earlier proposals developed by Congresswoman Nancy Pelosi and Senator Tom Daschle, and started in January 2006. There are two ways for participants to enroll in Medicare part D:

  1. Medicare Advantage prescription drug plans (MA-PDs), which comes along with other Medicare benefits (ex: Part A or Part B)
  2. Stand-alone prescription drug plan (PDP)

That means that for those who have already enrolled in Medicare (either >= 65 years old or having certain diseases such as end-stage-renal-disease or other disabilities), they are eligible to join the Part D. (For more information on eligibility over 65 years old, click here and for Medicare eligibility for those under 65, click here). For people enrolled in other insurance plan, they may also be eligible to apply for the plan. (For more information on how Medicare works with other types of insurance, click here).

Opioid information

First, let’s download the opioid prescriber data from the years 2013-2016, which is available from the CMS website as an application programming interface (API).

To do this, you can type “opioid” in the CMS website.. The following is what you will see:

Now you can click on the “Medicare Part D Opioid Prescriber Summary File 2013”, and you will be directed to the next page:
Further, you can click on the “Export”, and choose the “csv”, you will be guided to the download link. This is how we found the api link for downloading the data. The screen shot is shown as below:

There is a description about the variables. It can be found in the same page mentioned above. Here is a screenshot showing how you can find the information. For your convenience, we have saved it as a csv file (prescriberopioiddescription.csv) so that you can understand the meanings of the variables easily. This file describes what data is contained in each column. We use the commands in the kableExtra package to show the file to give us a nice display of the table in the windows.
The files we just downloaded contain the following information:

Column Name Description
NPI National Provider Identifier
NPPES Provider Last/Org Name Last Name/Organization Name of the Provider
NPPES Provider First Name First Name of the Provider
NPPES Provider Zip Code Zip Code of the Provider
NPPES Provider State State Code of the Provider
Specialty Description Provider Specialty Type
Total Claim Count The number of Medicare Part D drug claims, including original prescriptions and refills.
Opioid Claim Count The number of Medicare Part D opioid drug claims, including original prescriptions and refills. For a list of drugs that include opioids, visit <https://www.cms.gov/Research-Statistics-Data-and-Systems/Statistics-Trends-and-Reports/Medicare-Provider-Charge-Data/Downloads/PartD_DrugCatList_2014.zip.>;
Opioid Prescribing Rate The number of Opioid Claims divided by the Overall Claims and multiplied by 100.

Data Import

At this stage, you’ve downloaded your data from CMS API successfully. Now, what you need is to load or read these data in R. There are several base R functions that allow you read your data into R, which you may be familiar with such as read.table(), read.csv(), and read.delim(). Instead of using these, we will use the functions in the readr R package. The main reasons for this are

  1. Compared to equivalent base R functions, the functions in readr are around 10x faster.
  2. You can specify the column types (e.g character, integer, double, logical, date, time, etc)
  3. All parsing problems are recorded in a data frame.

The main functions in readr include:

readr functions Description
read_delim() reads in a flat file data with a given character to separate fields
read_csv() reads in a CSV file
read_tsv() reads in a file with values separated by tabs
read_lines() reads only a certain number of lines from the file
read_file() reads a complete file into a string
write_csv() writes data frame to CSV

A useful cheatsheet for the functions in the readr package can be found on RStudio’s website:

Data Wrangling

Combining the functions in the packages dplyr and kableExtra can help us take a glance at the data. Here, we use the mutate to generate a new character variable named NPI and use the kable() and kable_styling to make the display clearer.

NPI NPPES Provider Last Name NPPES Provider First Name NPPES Provider ZIP Code NPPES Provider State Specialty Description Total Claim Count Opioid Claim Count Opioid Prescribing Rate Extended-Release Opioid Claims Extended-Release Opioid Prescribing Rate
1003000126 ENKESHAFI ARDALAN 21502 MD Internal Medicine 545 23 4.22 NA NA
1003000142 KHALIL RASHID 43623 OH Anesthesiology 1733 1004 57.93 63 6.27
1003000167 ESCOBAR JULIO 89403 NV Dentist 49 11 22.45 0 0.00
1003000282 BLAKEMORE ROSIE 37243 TN Nurse Practitioner 146 NA NA 0 NA
1003000407 GIRARDI DAVID 15825 PA Family Practice 2225 17 0.76 0 0.00
1003000423 VELOTTA JENNIFER 44106 OH Obstetrics & Gynecology 170 NA NA 0 NA

We can see that the data is structured as provider-based level, meaning that the information in each role is for the specific health care provider. In this project, we’re going to do the analysis at State level, so you can probably imagine that we need to have some process to get State-level information from this data. Before moving there, let’s take a look at how big the data is for the 2016 information:

[1] 1131550      11

Wow! There are 1131550 health providers listed in this file. Of note, not every health provider had prescribed opioid in the year 2016.

1. Add State information

In many cases, we want to add basic information about States, such as State name, Region, and State abbreviation in our dataset. We can get this information easily using the dataset state in the library datasets. However, before taking advantage of the state, we need to take a look at our data, and have an idea about whether we can adopt the information in state directly.
#### How many States are there in the 2016 prescription dataset?

 [1] "MD" "OH" "NV" "TN" "PA" "CO" "FL" "OK" "CA" "TX" "OR" "KY" "SC" "CT" "NY"
[16] "NJ" "NC" "MI" "MA" "MS" "VA" "WA" "NM" "NH" "IA" "MN" "NE" "DC" "GA" "HI"
[31] "LA" "ND" "IN" "AZ" "IL" "AL" "PR" "AR" "KS" "RI" "WI" "ID" "MO" "WV" "VT"
[46] "UT" "ME" "AE" "MT" "DE" "WY" "SD" "AK" "ZZ" "GU" "VI" "MP" "AA" "AP" "XX"
[61] "AS"

There are 61 values for NPPES Provider State. From the manual, we know that other than the fifty States and DC, there are the other 10 values as following:

Values for NPPES Provider State Description
XX Unknown
AA Armed Forces Central/South America
AE Armed Forces Europe
AP Armed Forces Pacific
AS American Samoa
GU Guam
MP Northern Mariana Islands
PR Puerto Rico
VI Virgin Islands
ZZ Foreign Country

Add the information (State name, region, and abbreviation) to the state in the datasets

 [1] "Alabama"        "Alaska"         "Arizona"        "Arkansas"      
 [5] "California"     "Colorado"       "Connecticut"    "Delaware"      
 [9] "Florida"        "Georgia"        "Hawaii"         "Idaho"         
[13] "Illinois"       "Indiana"        "Iowa"           "Kansas"        
[17] "Kentucky"       "Louisiana"      "Maine"          "Maryland"      
[21] "Massachusetts"  "Michigan"       "Minnesota"      "Mississippi"   
[25] "Missouri"       "Montana"        "Nebraska"       "Nevada"        
[29] "New Hampshire"  "New Jersey"     "New Mexico"     "New York"      
[33] "North Carolina" "North Dakota"   "Ohio"           "Oklahoma"      
[37] "Oregon"         "Pennsylvania"   "Rhode Island"   "South Carolina"
[41] "South Dakota"   "Tennessee"      "Texas"          "Utah"          
[45] "Vermont"        "Virginia"       "Washington"     "West Virginia" 
[49] "Wisconsin"      "Wyoming"       
NPPES Provider State state_name region
MD Maryland South
OH Ohio North Central
NV Nevada West
TN Tennessee South
PA Pennsylvania Northeast
CO Colorado West
FL Florida South
OK Oklahoma South
CA California West
TX Texas South
OR Oregon West
KY Kentucky South
SC South Carolina South
CT Connecticut Northeast
NY New York Northeast
NJ New Jersey Northeast
NC North Carolina South
MI Michigan North Central
MA Massachusetts Northeast
MS Mississippi South
VA Virginia South
WA Washington West
NM New Mexico West
NH New Hampshire Northeast
IA Iowa North Central
MN Minnesota North Central
NE Nebraska North Central
DC District of Columbia South
GA Georgia South
HI Hawaii West
LA Louisiana South
ND North Dakota North Central
IN Indiana North Central
AZ Arizona West
IL Illinois North Central
AL Alabama South
PR Puerto Rico Others
AR Arkansas South
KS Kansas North Central
RI Rhode Island Northeast
WI Wisconsin North Central
ID Idaho West
MO Missouri North Central
WV West Virginia South
VT Vermont Northeast
UT Utah West
ME Maine Northeast
AE Armed Forces Europe Others
MT Montana West
DE Delaware South
WY Wyoming West
SD South Dakota North Central
AK Alaska West
ZZ Foreign Country Others
GU Guam Others
VI Virgin Islands Others
MP Northern Mariana Islands Others
AA Armed Forces Central/South America Others
AP Armed Forces Pacific Others
XX Unknown Others
AS American Samoa Others

2. Add population information for each State

Since it’ reasonable to have more opioid claims simply due to more participants enrolled in the Part D, we may want to compare the opioid prescription per 100 enrollments instead of total number of opioid prescriptions across States. Thus, one of the questions we are interested in is what’s the distribution of opioid prescription per 100 enrollments by States. To answer our question, other than the opioid claim information we’ve already got, we also need the information about how many participants enrolled in the Part D plan for each State. To the best of our knowledge, we can get the 2015 enrollment information from the publicly available CMS website.
(Note: The information is based on 2015. Please let us know if there are year-by-year State-level Part D enrollment information, so that we can update this analysis.)

Now, we can add the number of enrollments in Part D by State from population to the States information dataset states.
Note that there is some difference in the names of States between population and states. They are “Pending State Designation” and “Foreign and Other Outlying Areas”. Thus, in the further analysis, we can consider if we want to add them in or exclude them.

 [1] "Alabama"                          "Alaska"                          
 [3] "Arizona"                          "Arkansas"                        
 [5] "California"                       "Colorado"                        
 [7] "Connecticut"                      "Delaware"                        
 [9] "District of Columbia"             "Florida"                         
[11] "Georgia"                          "Hawaii"                          
[13] "Idaho"                            "Illinois"                        
[15] "Indiana"                          "Iowa"                            
[17] "Kansas"                           "Kentucky"                        
[19] "Louisiana"                        "Maine"                           
[21] "Maryland"                         "Massachusetts"                   
[23] "Michigan"                         "Minnesota"                       
[25] "Mississippi"                      "Missouri"                        
[27] "Montana"                          "Nebraska"                        
[29] "Nevada"                           "New Hampshire"                   
[31] "New Jersey"                       "New Mexico"                      
[33] "New York"                         "North Carolina"                  
[35] "North Dakota"                     "Ohio"                            
[37] "Oklahoma"                         "Oregon"                          
[39] "Pennsylvania"                     "Rhode Island"                    
[41] "South Carolina"                   "South Dakota"                    
[43] "Tennessee"                        "Texas"                           
[45] "Utah"                             "Vermont"                         
[47] "Virginia"                         "Washington"                      
[49] "West Virginia"                    "Wisconsin"                       
[51] "Wyoming"                          "American Samoa"                  
[53] "Guam"                             "Northern Mariana Islands"        
[55] "Puerto Rico"                      "Virgin Islands"                  
[57] "Pending State Designation"        "Foreign and Other Outlying Areas"
[59] "Total"                           

Now, we can combine the population information with the state, and save it as a new data frame called populationstate

Let’s see what the populationstate looks like.

NPPES Provider State state_name region enrollment_num2015
MD Maryland South 544529
OH Ohio North Central 1634697
NV Nevada West 294927
TN Tennessee South 903638
PA Pennsylvania Northeast 1878311
CO Colorado West 548360

Can you tell how many States do we have the information about number of enrollments in Part D ?

[1] 56

3. Glimpse at opioid information

In the dataset prescription_2016, we have information about total claim count, opioid claim count, and extended-release opioid claims. For this project, we only need to look at opioid claim count and total claim count.

[1] 0
[1] 319003

We noticed that there are some missing values due in Opioid Claim Count. This tells us that not every provider included in this dataset is eligible to prescribe opioid. Thus, in the next step, when we want to calculate the opioid prescription rate by State, we need to limit our data to those providers with both total claim information and opioid claim information.

4. Calculate the opioid prescription rate

Great! Now we have better idea about our dataset, and we need to create a dataset containing the information we need to answer our questions. In other words, we want to create a dataset for each year with following information:

Variable Name Description
NPPES Provider State State Abbreviation
total_opioid_claim Total opioid claims (Part D) in the State
total_claim_count Total claims (Part D) in the State
state_opioid_prescribing_rate The proportion of total opioid claims versus total claims (Part D) in the State
state_name State Name
region The region of the State
enrollment_num2015 Number of Part D enrollments in 2015
total_claim_bypop Total claims per 100 enrollment (*)
opioid_claim_bypop Opioid claims per 100 enrollment (*)
year year of the data came from

(*) These numbers are valid only for year 2015.

Since we’re going to use the same chuck of codes many times, we can write a function named anadata to save our times!

Here, we write a loop to execute the repetitive procedures. The alternative to do it is to implement some commands in the package purrr. [ Here is the cheatsheet for using purrr]

Now, we’re ready for our next step - data visualization!

Data Visualization

1. Comparing total opioid prescriptions in 2016

The first task is to understand the opioid prescriptions by States in 2016. We are going to use the functions in the library ggplot2 to help us plot the bar chart.

It’s nice to visualize all the information we have from this dataset. However, based on our original questions, we may want to focus on the 50 States and DC. Since for all the regions other than the 50 States and DC, they were labelled as Others in their region variable, we can limit the analysis based on them using the filter .

You may wonder why the labels on the y-axis are 6e+06 , 4e+06 , …, which are relatively hard to read. Here comes one potential solution - using the scale_y_continuous(labels = comma) in the library scales. This function will force the display of labels in y-axis be an easy-to-read number.

You may feel it’s hard to read since you need to either tilt your head or have a special ability to read the labels of States in the x-axis. Here, we provide one way to rotate this bar chart using coord_flip() .

(1) What are the top five States with the highest and lowest opioid prescription claims in Part D in 2016?

Based on the plot above, California, Florida, Texas, Pennsylvania, and Michigan are the top five States with the highest opioid prescription claims in Part D in 2016. And the top five States with the lowest opioid prescription claims in Part D in 2016 are District of Columbia, Alaska, Wyoming, Vermont, and Hawaii.

(3) Are you satisfied with the plots?

The plots did show the numbers of total opioid claims right. However, the audience need to read the x-axis carefully. Otherwise, they may misinterpret the results since the scales are so different. In this case, it may be a good idea to show a table with the numbers.

state_name total_opioid_claim
California 6956583
Florida 5568389
Texas 5012297
Pennsylvania 3525981
Michigan 3337506
Hawaii 155670
Vermont 146706
Wyoming 104558
Alaska 82557
District of Columbia 79879

Alternatively, you can show the top 5 by

state_name total_opioid_claim
California 6956583
Florida 5568389
Texas 5012297
Pennsylvania 3525981
Michigan 3337506

And you can show the lower 5 by

state_name total_opioid_claim
Hawaii 155670
Vermont 146706
Wyoming 104558
Alaska 82557
District of Columbia 79879

(4) How do you feel about the results? Do the results surprise you?

Probably you’re not surprised by the results, since the population in California, Florida, and Texas is large, and the population in District of Columbia, Alaska, and Wyoming is small.
To make a fair comparison across different States, we may want to adjust for “size of States.” There are many good options to achieve this goal. In this case study, we provide two potential methods:

  1. Create a variable called opioid prescription rate (defined by CMS). Opioid prescription rate is the proportion of opioid claims among the total claims in a certain year. Since total claims can be a proxy of the number of enrollments in Part D, opioid prescription rate can be considered as a fair comparison across States.

  2. Create a variable called opioid prescription claims per 100 enrollments . Since the enrollment number by States was available in 2015, we can create this variable to directly adjust for the population size. (Please let us know if there’s any publicly available information about Part D enrollment by States in the other years.)

To visualize our hypothesis, we will have two plots:
(1) The plot showing the number of enrollments versus number of opioid claims

  1. The plot showing the number of total claims versus number of opioid claims

3. Trend of opioid prescription rate in 2013 - 2016

We may want to see the trend of opioid prescription rate during 2013 and 2016 by State.

Visualize the change by States using bar chart

Here, we append the data from different years in long format first, and then plot the trend of opioid prescription rate.

### Visualize/Animate the change by States using bar chart

The alternative approach is to animate ther results using gganimate.

# <Ref 1> https://gganimate.com/articles/gganimate.html
# <Ref 2> https://towardsdatascience.com/create-animated-bar-charts-using-r-31d09e5841da
library(gganimate)
library(gifski)

data4animation <-  prescriber2016byState %>% 
        union(.,prescriber2015byState) %>%
        union(.,prescriber2014byState) %>%
        union(.,prescriber2013byState) %>%
        filter(region != "Others") %>%
        group_by(year) %>%
        mutate(rank = rank(-state_opioid_prescribing_rate),
               value_rel = state_opioid_prescribing_rate/state_opioid_prescribing_rate[rank==1],
               value_std = round(state_opioid_prescribing_rate,2)) %>%
        group_by(state_name) %>% 
        filter(rank <= 20) %>% # choose the top 20
        ungroup()

staticplot = ggplot(data4animation, 
                    aes(rank, 
                        group = state_name, 
                        fill = as.factor(state_name), 
                        color = as.factor(state_name))) +
  geom_tile(aes(y = round(state_opioid_prescribing_rate/2,2),
                height = round(state_opioid_prescribing_rate,2),
                width = 0.9), alpha = 0.8, color = NA) +
  geom_text(aes(y = 0, label = paste(state_name, " ")), vjust = 0.2, hjust = 1) +
  geom_text(aes(y= value_std,
                label = value_std, hjust=0)) +
  coord_flip(clip = "off", expand = FALSE) +
  scale_y_continuous(labels = scales::comma) +
  scale_x_reverse() +
  guides(color = FALSE, fill = FALSE) +
  theme(axis.line=element_blank(),
        axis.text.x=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks=element_blank(),
        axis.title.x=element_blank(),
         axis.title.y=element_blank(),
        legend.position="none",
        panel.background=element_blank(),
        panel.border=element_blank(),
        panel.grid.major=element_blank(),
        panel.grid.minor=element_blank(),
        panel.grid.major.x = element_line( size=.1, color="grey" ),
        panel.grid.minor.x = element_line( size=.1, color="grey" ),
        plot.title=element_text(size=10, hjust=0.5, face="bold", colour="grey", vjust=-1),
        plot.subtitle=element_text(size=6, hjust=0.5, face="italic", color="grey"),
        plot.caption =element_text(size=6, hjust=0.5, face="italic", color="grey"),
        plot.background=element_blank()  ,
       plot.margin = margin(2,2, 1, 3, "cm"))

staticplot

In general, the trend the opioid prescription rate was decreasing during 2013 - 2016 across most of the States.

4. Comparing opioid prescription by States in 2015

Since there are many policies made at State level, and it’s relatively difficult to get information about the policy in militaries, foreign countries, and unknown areas, we may want to focus on the areas we are able to get the information about the number of Part D Part enrollment.

Do two methods give us same information?

The opioid prescription rate was high in American Samoa, but the opioid prescription per 100 enrollments is low in American Samoa. This may be due to there are relatively few total claims in American Samoa, but the proportion of opioid prescription is high. The opioid prescription rates in Utah, Nevada, Oklahoma, Alabama, Idaho, Colorado, Tennessee, and Oregon are also relatively high. The opioid prescription per 100 enrollments are relatively high in Tennessee, Alabama, and Oklahoma.

Can you visualize the information from these two methods?

To visualize the information from these two methods, we propose to compare the “rankings” from two methods. First, we will create one variable called rank_method1, which is the rank based on the method I (state opioid prescription rate), and the other variable called rank_method2 , which is the rank based on the method II (opioid claim by number of enrollment). This can be done by using the dense_rank(). Then, we can have an x-y plot showing the ranking between these two methods.

nppes provider state total_opioid_claim total_claim_count state_opioid_prescribing_rate state_name region enrollment_num2015 total_claim_bypop opioid_claim_bypop year rank_method1 rank_method2
TN 2923689 36817973 7.940929 Tennessee South 903638 4074.416 323.5465 2015 7 1
AL 2179506 26521232 8.217967 Alabama South 681722 3890.329 319.7060 2015 4 2
OK 1286402 15645299 8.222291 Oklahoma South 442217 3537.923 290.8984 2015 3 3
AR 1132475 16230105 6.977620 Arkansas South 403326 4024.066 280.7840 2015 17 4
MS 1083075 16386685 6.609482 Mississippi South 392353 4176.516 276.0461 2015 24 5
KY 1710346 27234066 6.280171 Kentucky South 630711 4317.994 271.1774 2015 31 6

You can tell that these two methods are consistent with some exceptions. One potential reason is that the population composition in each State is different, making the distributions of total prescriptions different. Take State A, with more older residents (>= 80 y/o), and State B, with fewer older residents (>= 80 y/o). Then, it’s understandable that the average total prescriptions per person in State A may be higher than the average total prescriptions per person in State B. There are pros and cons of these two different methods, and which should we use is highly dependent on the questions you want to address.

You may want to also add the information about number of enrollments in the plot. Here, we provide one potential way to do it - making the size of the dot proportional to the number of enrollment. This can be achieved by geom_point(aes(size = THEVARIABLEYOUWANTTOPUT )).

5. Let’s put it on the map!

In many cases, you may want to integrate your information on a map so that don’t need to map the information on the bar chart to the U.S. map in your brain. Here, we will use the choroplethr and choroplethrMaps to help us achieve this goal. There is a nice website introducing these packages. The other common approach is to use ggmap, which may ask you to apply for a Google API key in advance.

Step 1: Get the location information for each State

We have done this earlier. This means that the dataset state has been edited by us. To use the choroplethrMaps, we need the original state dataset, so we call the library again, and ask for the original state dataset.

 [1] "Alabama"        "Alaska"         "Arizona"        "Arkansas"      
 [5] "California"     "Colorado"       "Connecticut"    "Delaware"      
 [9] "Florida"        "Georgia"        "Hawaii"         "Idaho"         
[13] "Illinois"       "Indiana"        "Iowa"           "Kansas"        
[17] "Kentucky"       "Louisiana"      "Maine"          "Maryland"      
[21] "Massachusetts"  "Michigan"       "Minnesota"      "Mississippi"   
[25] "Missouri"       "Montana"        "Nebraska"       "Nevada"        
[29] "New Hampshire"  "New Jersey"     "New Mexico"     "New York"      
[33] "North Carolina" "North Dakota"   "Ohio"           "Oklahoma"      
[37] "Oregon"         "Pennsylvania"   "Rhode Island"   "South Carolina"
[41] "South Dakota"   "Tennessee"      "Texas"          "Utah"          
[45] "Vermont"        "Virginia"       "Washington"     "West Virginia" 
[49] "Wisconsin"      "Wyoming"       

Summary

California, Florida, Texas, Pennsylvania, and Michigan are the top five States with the highest opioid prescription claims in Part D in 2016. However, after taking the population of the States into account, they were not the top five States with the highest opioid prescription rates. Instead, Nevada, Utah, Alabama, Oklahoma, Idaho had the highest opioid prescription claims per 100 enrollments. In general, the trend the opioid prescription rate was decreasing during 2013 - 2016 across most of the States. However, the data for this analysis came from Medicare Part D, and thus opioid prescription information for relatively younger adults was missing in the analysis. Combining these data with opioid-related policies across States may be more informative.

Appendix

There are at least two extentions you can make from this case study.
The first one is linking this with more publicly available data. The second one is to demonstrate longitudinal data analysis.

Extension 1 : Additional data source

Medicare Part D beneficiaries information is publicly available, and may provide additional information you are interested in. The information about Medicare Part D beneficiaries are publicly available. Here, we demonstrate how to download file from the website directly using the method as the aforementioned. However, this is only for demonstration purpose, and not going to be used in this project.

The following is the code book. In other words, the description of the variables in the dataset we just downloaded is summarized in the following table: (Of note, NPI stands for National Provider Identifier, and NPPES stands for CMS National Plan and Provider Enumeration System. In general, healthcare providers have their unique 10-digit NPIs to identify themselves, and more information can be found in the NPI Registry Public Search)

Column Name Description
npi National Provider Identifier
nppes_provider_last_org_name Last Name/Organization Name of the Provider
nppes_provider_first_name First Name of the Provider
nppes_provider_city City of the Provider
nppes_provider_state State Code of the Provider
specialty_description Provider Specialty Type
description_flag Source of Provider Specialty
drug_name Brand Name
generic_name USAN Generic Name - Short Version
bene_count Number of Medicare Beneficiaries
total_claim_count Number of Medicare Part D Claims, Including Refills
total_30_day_fill_count Number of Standardized 30-Day Fills, Including Refills
total_day_supply Number of Day’s Supply for All Claims
total_drug_cost Aggregate Cost Paid for All Claims
bene_count_ge65 Number of Medicare Beneficiaries Age 65+
bene_count_ge65_suppress_flag Reason for Suppression of Bene_Count_Ge65
total_claim_count_ge65 Number of Claims, Including Refills, for Beneficiaries Age 65+
ge65_suppress_flag Reason for Suppression of Total_Claim_Count_Ge65, Total_30_Day_Fill_Count_Ge65, Total_Day_Supply_Ge65, and Total_Drug_Cost_Ge65
total_30_day_fill_count_ge65 Number of Standardized 30-Day Fills, Including Refills, for Beneficiaries Age 65+
total_day_supply_ge65 Number of Day’s Supply for All Claims for Beneficiaries Age 65+
total_drug_cost_ge65 Aggregate Cost Paid for All Claims for Beneficiaries Age 65+

Extension 2 : Longitudinal data analysis

The above plots showing the longitudinal trend may inspire you the following questions:

  1. Is the region associated with the opioid prescription rate at the baseline (aka, at year 2013)?

  2. Is the region associated with the rate of decline in opioid prescription rate across time during 2013 - 2016?

These are all great questions, but we are not going to discuss about this deeply in this case study. If you are interested in these questions, we would recommend you to read some materials about longitudinal data analysis. For your convenience, we do provide some sample codes. We will run two linear mixed effect models using the package lme4, and provide brief interpretation. In the first model fit1, we are investigating whether the region is associated with the opioid prescription rate in the year 2013 while we don’t allow the change of opioid prescription rate to be differed by region. In the second model fit2, we are investigating whether the region is associated with the opioid prescription rate in the year 2013 and whether region associated with the rate of decline in opioid prescription rate across time during 2013 - 2016 at the same time while we allow the change of opioid prescription rate to be differed by regions.
( Note: The instructors still need to add the interpretation of random intercept and random slope.)

Linear mixed model fit by REML ['lmerMod']
Formula: state_opioid_prescribing_rate ~ as.factor(region) + interval +  
    (1 | state_name)
   Data: datamodel

REML criterion at convergence: 69.1

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.4733 -0.5243  0.0713  0.6071  2.5069 

Random effects:
 Groups     Name        Variance Std.Dev.
 state_name (Intercept) 0.93704  0.9680  
 Residual               0.02214  0.1488  
Number of obs: 204, groups:  state_name, 51

Fixed effects:
                            Estimate Std. Error t value
(Intercept)                 6.354847   0.280613  22.646
as.factor(region)Northeast -0.835871   0.428111  -1.952
as.factor(region)South      0.773766   0.366052   2.114
as.factor(region)West       1.269896   0.388657   3.267
interval                   -0.169917   0.009318 -18.236

Correlation of Fixed Effects:
            (Intr) as.()N as.()S as.()W
as.fctr(r)N -0.654                     
as.fctr(r)S -0.765  0.501              
as.fctr(r)W -0.720  0.472  0.552       
interval    -0.050  0.000  0.000  0.000
Linear mixed model fit by REML ['lmerMod']
Formula: state_opioid_prescribing_rate ~ as.factor(region) * interval +  
    interval + (1 + interval | state_name)
   Data: datamodel

REML criterion at convergence: 32

Scaled residuals: 
     Min       1Q   Median       3Q      Max 
-1.96922 -0.57516 -0.06762  0.56844  1.95501 

Random effects:
 Groups     Name        Variance Std.Dev. Corr 
 state_name (Intercept) 1.038002 1.01882       
            interval    0.006639 0.08148  -0.45
 Residual               0.010294 0.10146       
Number of obs: 204, groups:  state_name, 51

Fixed effects:
                                      Estimate Std. Error t value
(Intercept)                          6.3729408  0.2951282  21.594
as.factor(region)Northeast          -0.7965514  0.4508158  -1.767
as.factor(region)South               0.7735943  0.3854653   2.007
as.factor(region)West                1.1719152  0.4092692   2.863
interval                            -0.1819800  0.0269231  -6.759
as.factor(region)Northeast:interval -0.0262130  0.0411257  -0.637
as.factor(region)South:interval      0.0001146  0.0351641   0.003
as.factor(region)West:interval       0.0653206  0.0373356   1.750

Correlation of Fixed Effects:
            (Intr) as.()N as.()S as.()W intrvl a.()N: a.()S:
as.fctr(r)N -0.655                                          
as.fctr(r)S -0.766  0.501                                   
as.fctr(r)W -0.721  0.472  0.552                            
interval    -0.428  0.280  0.327  0.308                     
as.fctr()N:  0.280 -0.428 -0.214 -0.202 -0.655              
as.fctr()S:  0.327 -0.214 -0.428 -0.236 -0.766  0.501       
as.fctr()W:  0.308 -0.202 -0.236 -0.428 -0.721  0.472  0.552

From these models, we can conclude that the opioid prescription rate was decreasing over time during 2013 - 2016. Though there are some difference in the opioid prescription rate across different regions at the baseline (in the year 2013), there is no obvious difference in the trend of decline across different regions.

LS0tDQp0aXRsZTogT3BlbkNhc2VTdHVkaWVzIC0gT3Bpb2lkIChNZWRpY2FyZSkgICAgDQpvdXRwdXQ6IA0KICAgIGh0bWxfZG9jdW1lbnQ6DQogICAgICAgIHRoZW1lOiBjb3NtbyANCiAgICAgICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgICAgIHRvYzogdHJ1ZQ0KICAgICAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICAgICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgICAgICBudW1iZXJfc2VjdGlvbnM6IGZhbHNlDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoaW5jbHVkZSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgIA0KICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBlY2hvID0gVFJVRSkNCmBgYA0KICAgICANCmBgYHtyIGVjaG89RkFMU0UsIG91dC53aWR0aD0nMTAwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygnLi9pbWcvb3Bpb2lkbWFwLnBuZycpDQpgYGANCg0KYCFbXSgiZ2dhbmltLmdpZiIpYCBuZWVkcyB0byBiZSBmaXhlZC4gDQogICAgIA0KIyBNb3RpdmF0aW9uICANCg0KT3Bpb2lkIHByZXNjcmlwdGlvbiBoYXMgYmVjb21lIGEgcG9wdWxhciB0b3BpYyBiZWNhdXNlIG9mIA0KdGhlIGluY3JlYXNpbmcgcHJlc2NyaXB0aW9uIGFuZCBjb25jZXJucyBhYm91dCBvdmVyZG9zZSwgDQpvcGlvaWQtcmVsYXRlZCBkZWF0aHMsIGFuZCBvdGhlciBvcGlvaWQtYXNzb2NpYXRlZCBzaWRlIA0KZWZmZWN0cy4gKFJlZjogW1BhdWxvenppIGV0IGFsLiAyMDExXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3B1Ym1lZC8yMjA0ODczMCksIA0KW1J1ZGQgZXQgYWwuIDIwMTZdKGh0dHBzOi8vd3d3Lm5jYmkubmxtLm5paC5nb3YvcHVibWVkLzI4MDMzMzEzKSwgDQpbUnVkZCBldCBhbC4gMjAxNl0oaHR0cHM6Ly93d3cubmNiaS5ubG0ubmloLmdvdi9wdWJtZWQvMjY3MjA4NTcpLCANCltTb2xvbW9uIGV0IGFsLiAyMDEwXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3B1Ym1lZC8yMTE0OTc1NCksIA0KW0R1bm4sIGV0IGFsLiAyMDEwXShodHRwczovL3d3dy5uY2JpLm5sbS5uaWguZ292L3B1Ym1lZC8yMDA4MzgyNykuICkgICAgIA0KT3VyIG1vdGl2YXRpb24gaXMgdG8gdW5kZXJzdGFuZCB0aGUgb3Bpb2lkIHByZXNjcmlwdGlvbiBpbiB0aGUgU3RhdGVzIA0KdXNpbmcgcHVibGljbHkgYXZhaWxhYmxlIGRhdGEuIFRodXMsIHRoZSBtYWluIHF1ZXN0aW9ucyB3ZSBhcmUgZ29pbmcgdG8gYXNrIA0KaW5jbHVkZTogIA0KICAgICAgICAgIA0KKDEpIEFtb25nIHRoZSA1MCBTdGF0ZXMgYW5kIERpc3RyaWN0IG9mIENvbHVtYmlhLCANCndoaWNoIGZpdmUgU3RhdGVzIGhhZCB0aGUgaGlnaGVzdCBhbmQgbG93ZXN0IG51bWJlciBpbiAgICANCiAgICAoYSkgKipUb3RhbCBvcGlvaWQgY2xhaW1zKiogLCAgIA0KICAgIChiKSAqKk9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSoqIA0KKCA9IHRvdGFsIG9waW9pZCBjbGFpbXMgLyB0b3RhbCBjbGFpbXMgKSAsIGFuZCAgICANCiAgICAoYykgKipPcGlvaWQgcHJlc2NyaXB0aW9uIHBlciAxMDAgZW5yb2xsbWVudHMqKiA/ICAgICAgIA0KICAgICAgICANCigyKSBEaWQgdGhlIHRvdGFsIG51bWJlciBvZiBvcGlvaWQgcHJlc2NyaXB0aW9ucyBjaGFuZ2Ugb3ZlciB0aW1lPyAgICANCiAgICAgICANCigzKSBDYW4geW91IHZpc3VhbGl6ZSB0aGUgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlIG9uIHRoZSBVLlMgbWFwPyAgIA0KDQoNCkluIHRoaXMgY2FzZSBzdHVkeSwgd2UnbGwgd2FsayB5b3UgdGhyb3VnaCBjb2xsZWN0aW5nIGRhdGEsIA0KaW1wb3J0aW5nIGRhdGEsIHdyYW5nbGluZyBkYXRhLCBhbmQgdmlzdWFsaXppbmcgdGhlIGRhdGEsIA0KdXNpbmcgdGhlIHdlbGwtZXN0YWJsaXNoZWQgYW5kIGNvbW1vbmx5IHVzZWQgcGFja2FnZXMsIGluY2x1ZGluZyANCmBrYWJsZUV4dHJhYCwgIGByZWFkcmAgLCBgdGlkeXZlcnNlYCAsIGBkYXRhc2V0c2AgLCBgZ2dwbG90MmAgLCANCmBzY2FsZXNgICwgYGdncmVwZWxgICwgYGNob3JvcGxldGhyYCAsIGFuZCBgY2hvcm9wbGV0aHJNYXBzYCAuIA0KSGVyZSB3ZSBwcm92aWRlIGFuIG92ZXJ2aWV3IGFvYnV0IHRoZXNlIHBhY2thZ2VzIA0KYmVmb3JlIHdlIHN0YXJ0czogDQoNCnxSIHBhY2thZ2V8V2hhdCBjYW4gdGhlIHBhY2thZ2UgcHJvdmlkZT98DQp8LS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfA0KfGBrYWJsZUV4dHJhYHxIZWxwcyB3aXRoIGJ1aWxkaW5nIGNvbXBsZXggdGFibGVzIGFuZCBtYW5pcHVsYXRpbmcgdGFibGUgc3R5bGVzOyBjcmVhdGVzIGF3ZXNvbWUgSFRNTCB0YWJsZXN8DQp8YHJlYWRyYHxBbGxvd3MgeW91IHRvIHJlYWQgZGF0YSBmcm9tIHZhcmlvdXMgZm9ybWF0cyBmYXN0ZXJ8DQp8YHRpZHl2ZXJzZWB8UHJvdmlkZXMgdXNlci1mcmllbmRseSBkYXRhIG1hbmlwdWxhdGlvbnwNCnxgZGF0YXNldHNgfEdpdmVzIHVzIHVzZWZ1bCBpbmZvcm1hdGlvbiwgaW5jbHVkaW5nIHRoZSBTdGF0ZXMnIGluZm9ybWF0aW9ufA0KfGBnZ3Bsb3QyYHxJbXByb3ZlcyBkYXRhIHZpc3VhbGlzYXRpb25zfA0KfGBzY2FsZXNgfEFkZHMgdGhlIGZsZXhpYmlsaXR5IG9mIHNjYWxpbmd8DQp8YGdncmVwZWxgfEF2b2lkcyBzdXBlcmltcG9zaW5nIHRoZSBsZWdlbmRzIHlvdSBkb24ndCBleHBlY3R8DQp8YGNob3JvcGxldGhyYHxIZWxwcyBwcmVwYXJpbmcgZm9yIHBsb3R0aW5nIHRoZSBVLlMuIE1hcHwNCnxgY2hvcm9wbGV0aHJNYXBzYHxIZWxwcyB1cyBwbG90IHRoZSBVLlMuIE1hcHwNCg0KIyBXaGF0IGlzIHRoZSBkYXRhPyAgICAgIA0KUmVjZW50bHksIHRoZSBDZW50ZXJzIGZvciBNZWRpY2FyZSAmIE1lZGljYWlkIFNlcnZpY2VzIChDTVMpIGhhcyANCnByZXBhcmVkIGEgcHVibGljIGRhdGFzZXQsIGluY2x1ZGluZyBpbmZvcm1hdGlvbiBpbiB0aGUgcGFydCBEIGNvdmVyaW5nIA0KY2FsZW5kYXIgeWVhcnMgMjAxMyB0aHJvdWdoIDIwMTYsIHRvIG1ha2Ugb3VyIGhlYWx0aCBjYXJlIHN5c3RlbSBtb3JlIHRyYW5zcGFyZW50LCANCmFuZCB0byBhbGxvdyBjaXRpemVucyB0byB1bmRlcnN0YW5kIHRoZSBtZWRpY2FsIGV4cGVuZGl0dXJlIGFuZCANCnJlbGV2YW50IGhlYWx0aCBpc3N1ZXMuIFlvdSBjYW4gZmluZCB0aGUgZGVzY3JpcHRpb24gb2YgdGhlIGRhdGEgaGVyZTogIA0KW01lZGljYXJlIHBhcnQgRCBkYXRhc2V0XShodHRwczovL3d3dy5jbXMuZ292L1Jlc2VhcmNoLVN0YXRpc3RpY3MtRGF0YS1hbmQtU3lzdGVtcy9TdGF0aXN0aWNzLVRyZW5kcy1hbmQtUmVwb3J0cy9NZWRpY2FyZS1Qcm92aWRlci1DaGFyZ2UtRGF0YS9Eb3dubG9hZHMvUHJlc2NyaWJlcl9NZXRob2RzLnBkZikgIA0KDQpgYGB7ciBvdXQud2lkdGggPSAiOTUlIiwgZWNobyA9IEZBTFNFLCBvdXQud2lkdGg9JzkwJSd9DQoja25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImh0dHBzOi8vYXNwZS5oaHMuZ292L3N5c3RlbS9maWxlcy9pbWFnZXMtcmVwb3J0cy1iYXNpYy83MDQ0MS9maWcxLmpwZyIpDQpgYGANCg0KIyMgTWVkaWNhcmUgZGF0YSAoUGFydCBEKQ0KTWVkaWNhcmUgUGFydCBEIGlzIHByZXNjcmlwdGlvbiBkcnVnIGNvdmVyYWdlIHBsYW4gDQpydW4gYnkgQ2VudGVyIGZvciBNZWRpY2FyZSAmIE1lZGljYWlkIFNlcnZpY2VzIChDTVMpLiANCltIZXJlIGlzIGEgd2Vic2l0ZSBkZXNjcmliaW5nIHRoZSBpbmZvcm1hdGlvbiBhYm91dCBQYXJ0IERdKGh0dHBzOi8vd3d3Lm1lZGljYXJlLmdvdi9kcnVnLWNvdmVyYWdlLXBhcnQtZCkgDQpJdCB3YXMgb3JpZ2luYWxseSBwcm9wb3NlZCBieSBQcmVzaWRlbnQgQmlsbCBDbGludG9uIGluIDIwMDAgDQpiYXNlZCBvbiBlYXJsaWVyIHByb3Bvc2FscyBkZXZlbG9wZWQgYnkgQ29uZ3Jlc3N3b21hbiANCk5hbmN5IFBlbG9zaSBhbmQgU2VuYXRvciBUb20gRGFzY2hsZSwgYW5kIHN0YXJ0ZWQgaW4gDQpKYW51YXJ5IDIwMDYuIFRoZXJlIGFyZSB0d28gd2F5cyBmb3IgcGFydGljaXBhbnRzIHRvDQplbnJvbGwgaW4gTWVkaWNhcmUgcGFydCBEOiANCg0KMS4gTWVkaWNhcmUgQWR2YW50YWdlIHByZXNjcmlwdGlvbiBkcnVnIHBsYW5zIChNQS1QRHMpLCB3aGljaA0KY29tZXMgYWxvbmcgd2l0aCBvdGhlciBNZWRpY2FyZSBiZW5lZml0cyAoZXg6IFBhcnQgQSBvciBQYXJ0IEIpIA0KMi4gU3RhbmQtYWxvbmUgcHJlc2NyaXB0aW9uIGRydWcgcGxhbiAoUERQKQ0KDQpUaGF0IG1lYW5zIHRoYXQgZm9yIHRob3NlIHdobyBoYXZlIGFscmVhZHkgZW5yb2xsZWQgaW4gDQpNZWRpY2FyZSAoZWl0aGVyID49IDY1IHllYXJzIG9sZCBvciBoYXZpbmcgY2VydGFpbiBkaXNlYXNlcyANCnN1Y2ggYXMgZW5kLXN0YWdlLXJlbmFsLWRpc2Vhc2Ugb3Igb3RoZXIgZGlzYWJpbGl0aWVzKSwgdGhleSANCmFyZSBlbGlnaWJsZSB0byBqb2luIHRoZSBQYXJ0IEQuIA0KKFtGb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiBlbGlnaWJpbGl0eSBvdmVyIDY1IHllYXJzIG9sZCwgY2xpY2sgaGVyZV0oaHR0cHM6Ly93d3cuaGhzLmdvdi9hbnN3ZXJzL21lZGljYXJlLWFuZC1tZWRpY2FpZC93aG8taXMtZWxpYmlibGUtZm9yLW1lZGljYXJlL2luZGV4Lmh0bWwpDQphbmQgW2ZvciBNZWRpY2FyZSBlbGlnaWJpbGl0eSBmb3IgdGhvc2UgdW5kZXIgNjUsIGNsaWNrIGhlcmVdKGh0dHBzOi8vd3d3Lm1lZGljYXJlaW50ZXJhY3RpdmUub3JnL2dldC1hbnN3ZXJzL21lZGljYXJlLWJhc2ljcy9tZWRpY2FyZS1lbGlnaWJpbGl0eS1vdmVydmlldy9tZWRpY2FyZS1lbGlnaWJpbGl0eS1mb3ItdGhvc2UtdW5kZXItNjUpKS4gRm9yIHBlb3BsZSBlbnJvbGxlZCANCmluIG90aGVyIGluc3VyYW5jZSBwbGFuLCB0aGV5IG1heSBhbHNvIGJlIGVsaWdpYmxlIHRvIGFwcGx5DQpmb3IgdGhlIHBsYW4uIChbRm9yIG1vcmUgaW5mb3JtYXRpb24gb24gaG93IE1lZGljYXJlIHdvcmtzIA0Kd2l0aCBvdGhlciB0eXBlcyBvZiBpbnN1cmFuY2UsIGNsaWNrIGhlcmVdKGh0dHBzOi8vd3d3Lm1lZGljYXJlLmdvdi9kcnVnLWNvdmVyYWdlLXBhcnQtZC9ob3ctcGFydC1kLXdvcmtzLXdpdGgtb3RoZXItaW5zdXJhbmNlKSkuIA0KICAgICANCg0KIyMjIE9waW9pZCBpbmZvcm1hdGlvbiAgDQogICAgDQpGaXJzdCwgbGV0J3MgZG93bmxvYWQgdGhlIG9waW9pZCBwcmVzY3JpYmVyIGRhdGEgZnJvbSANCnRoZSB5ZWFycyAyMDEzLTIwMTYsIHdoaWNoIGlzIGF2YWlsYWJsZSBmcm9tIHRoZSBDTVMgDQp3ZWJzaXRlIGFzIGFuIGFwcGxpY2F0aW9uIHByb2dyYW1taW5nIGludGVyZmFjZSAoQVBJKS4gICANCg0KVG8gZG8gdGhpcywgeW91IGNhbiB0eXBlICJvcGlvaWQiIGluIA0KdGhlIFtDTVMgd2Vic2l0ZS5dKGh0dHBzOi8vZGF0YS5jbXMuZ292L2Jyb3dzZT9xPW9waW9pZCkuIA0KVGhlIGZvbGxvd2luZyBpcyB3aGF0IHlvdSB3aWxsIHNlZTogDQpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzEwMCUnfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJy4vaW1nL2luZm9ybWF0aW9uMDEuUE5HJykNCmBgYA0KICAgIA0KTm93IHlvdSBjYW4gY2xpY2sgb24gdGhlICJNZWRpY2FyZSBQYXJ0IEQgT3Bpb2lkIFByZXNjcmliZXIgU3VtbWFyeSBGaWxlIDIwMTMiLCBhbmQgDQp5b3Ugd2lsbCBiZSBkaXJlY3RlZCB0byB0aGUgbmV4dCBwYWdlOiAgDQpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzEwMCUnfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJy4vaW1nL2luZm9ybWF0aW9uMDIuUE5HJykNCmBgYA0KRnVydGhlciwgeW91IGNhbiBjbGljayBvbiB0aGUgIkV4cG9ydCIsIGFuZCBjaG9vc2UgdGhlICJjc3YiLCANCnlvdSB3aWxsIGJlIGd1aWRlZCB0byB0aGUgZG93bmxvYWQgbGluay4gVGhpcyBpcyBob3cgd2UgZm91bmQgDQp0aGUgYXBpIGxpbmsgZm9yIGRvd25sb2FkaW5nIHRoZSBkYXRhLiBUaGUgc2NyZWVuIHNob3QgaXMgc2hvd24gDQphcyBiZWxvdzogIA0KYGBge3IgZWNobz1GQUxTRSwgb3V0LndpZHRoPScxMDAlJ30NCmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCcuL2ltZy9pbmZvcm1hdGlvbjAzLlBORycpDQpgYGANCiAgICAgICAgIA0KYGBge3J9DQppZighZmlsZS5leGlzdHMoIi4vZGF0YS8yMDE2cHJlc2NyaWJlci5jc3YiKSl7DQogIGZpbGVfbGluayA8LSAiaHR0cHM6Ly9kYXRhLmNtcy5nb3YvYXBpL3ZpZXdzLzZ3Zzkta3dpcC9yb3dzLmNzdiINCiAgZG93bmxvYWQuZmlsZShmaWxlX2xpbmssDQogICAgICAgICAgICAgICAgZGVzdGZpbGUgPSAiLi9kYXRhLzIwMTZwcmVzY3JpYmVyLmNzdiIsbW9kZSA9ICJ3YiIpIA0KICB9DQoNCg0KaWYoIWZpbGUuZXhpc3RzKCIuL2RhdGEvMjAxNXByZXNjcmliZXIuY3N2Iikpew0KICBmaWxlX2xpbmsgPC0gImh0dHBzOi8vZGF0YS5jbXMuZ292L2FwaS92aWV3cy82aTJrLTdoOHAvcm93cy5jc3YiDQogIGRvd25sb2FkLmZpbGUoZmlsZV9saW5rLA0KICAgICAgICAgICAgICAgIGRlc3RmaWxlID0gIi4vZGF0YS8yMDE1cHJlc2NyaWJlci5jc3YiLG1vZGUgPSAid2IiKSANCiAgfQ0KDQppZighZmlsZS5leGlzdHMoIi4vZGF0YS8yMDE0cHJlc2NyaWJlci5jc3YiKSl7DQogIGZpbGVfbGluayA8LSAiaHR0cHM6Ly9kYXRhLmNtcy5nb3YvYXBpL3ZpZXdzL2U0a2EtM25jeC9yb3dzLmNzdiINCiAgZG93bmxvYWQuZmlsZShmaWxlX2xpbmssDQogICAgICAgICAgICAgICAgZGVzdGZpbGUgPSAiLi9kYXRhLzIwMTRwcmVzY3JpYmVyLmNzdiIsbW9kZSA9ICJ3YiIpIA0KICB9DQoNCmlmKCFmaWxlLmV4aXN0cygiLi9kYXRhLzIwMTNwcmVzY3JpYmVyLmNzdiIpKXsNCiAgZmlsZV9saW5rIDwtICJodHRwczovL2RhdGEuY21zLmdvdi9hcGkvdmlld3MveWIyai1mM2ZwL3Jvd3MuY3N2Ig0KICBkb3dubG9hZC5maWxlKGZpbGVfbGluaywNCiAgICAgICAgICAgICAgICBkZXN0ZmlsZSA9ICIuL2RhdGEvMjAxM3ByZXNjcmliZXIuY3N2Iixtb2RlID0gIndiIikgDQp9DQpgYGANCg0KVGhlcmUgaXMgYSBkZXNjcmlwdGlvbiBhYm91dCB0aGUgdmFyaWFibGVzLiANCkl0IGNhbiBiZSBmb3VuZCBpbiB0aGUgc2FtZSBwYWdlIA0KW21lbnRpb25lZCBhYm92ZS5dKGh0dHBzOi8vZGF0YS5jbXMuZ292L01lZGljYXJlLVBhcnQtRC9NZWRpY2FyZS1QYXJ0LUQtT3Bpb2lkLVByZXNjcmliZXItU3VtbWFyeS1GaWxlLTIwMS95YjJqLWYzZnApIA0KSGVyZSBpcyBhIHNjcmVlbnNob3Qgc2hvd2luZyBob3cgeW91IGNhbiBmaW5kIHRoZSBpbmZvcm1hdGlvbi4gDQpgYGB7ciBlY2hvPUZBTFNFLCBvdXQud2lkdGg9JzEwMCUnfQ0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoJy4vaW1nL2luZm9ybWF0aW9uMDQuUE5HJykNCmBgYA0KRm9yIHlvdXIgY29udmVuaWVuY2UsIHdlIGhhdmUgc2F2ZWQgaXQgYXMgYSBjc3YgDQpmaWxlIChgcHJlc2NyaWJlcm9waW9pZGRlc2NyaXB0aW9uLmNzdmApIHNvIHRoYXQgeW91IGNhbiANCnVuZGVyc3RhbmQgdGhlIG1lYW5pbmdzIG9mIHRoZSB2YXJpYWJsZXMgZWFzaWx5LiANClRoaXMgZmlsZSBkZXNjcmliZXMgd2hhdCBkYXRhIGlzIGNvbnRhaW5lZCBpbiBlYWNoIGNvbHVtbi4NCldlIHVzZSB0aGUgY29tbWFuZHMgaW4gdGhlIGBrYWJsZUV4dHJhYCBwYWNrYWdlIHRvIHNob3cgdGhlIGZpbGUgdG8gDQpnaXZlIHVzIGEgbmljZSBkaXNwbGF5IG9mIHRoZSB0YWJsZSBpbiB0aGUgd2luZG93cy4gIA0KVGhlIGZpbGVzIHdlIGp1c3QgZG93bmxvYWRlZCBjb250YWluIHRoZSBmb2xsb3dpbmcgaW5mb3JtYXRpb246ICAgIA0KYGBge3J9DQpsaWJyYXJ5KGthYmxlRXh0cmEpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCnBhcnRkaW5mb2Rlc2NyaXB0aW9uID0gcmVhZC5jc3YoIi4vZG9jMi9wcmVzY3JpYmVyb3Bpb2lkZGVzY3JpcHRpb24uY3N2IikNCm5hbWVzKHBhcnRkaW5mb2Rlc2NyaXB0aW9uKVsxXSA8LSAiQ29sdW1uIE5hbWUiDQoNCnBhcnRkaW5mb2Rlc2NyaXB0aW9uICU+JQ0KICBzZWxlY3QoYENvbHVtbiBOYW1lYCxEZXNjcmlwdGlvbikgICU+JQ0KICBrYWJsZSgpICU+JQ0KICBrYWJsZV9zdHlsaW5nKCkgJT4lDQogIGNvbHVtbl9zcGVjKDEsIGJvbGQgPSBULCBib3JkZXJfcmlnaHQgPSBULCBiYWNrZ3JvdW5kID0gIndoaXRlIikgJT4lDQogIGNvbHVtbl9zcGVjKDIsIHdpZHRoID0gIjMwZW0iLCBiYWNrZ3JvdW5kID0gImxpZ2h0eWVsbG93IikNCmBgYA0KDQoNCiMgRGF0YSBJbXBvcnQgDQoNCkF0IHRoaXMgc3RhZ2UsIHlvdSd2ZSBkb3dubG9hZGVkIHlvdXIgZGF0YSBmcm9tIA0KQ01TIEFQSSBzdWNjZXNzZnVsbHkuIE5vdywgd2hhdCB5b3UgbmVlZCBpcyB0byANCmBsb2FkYCBvciBgcmVhZGAgdGhlc2UgZGF0YSBpbiBSLiANClRoZXJlIGFyZSBzZXZlcmFsIGJhc2UgUiBmdW5jdGlvbnMgdGhhdCBhbGxvdyB5b3UgDQpyZWFkIHlvdXIgZGF0YSBpbnRvIFIsIHdoaWNoIHlvdSBtYXkgYmUgZmFtaWxpYXIgDQp3aXRoIHN1Y2ggYXMgYHJlYWQudGFibGUoKWAsIGByZWFkLmNzdigpYCwgDQphbmQgYHJlYWQuZGVsaW0oKWAuIEluc3RlYWQgb2YgdXNpbmcgdGhlc2UsIA0Kd2Ugd2lsbCB1c2UgdGhlIGZ1bmN0aW9ucyBpbiB0aGUgDQpbcmVhZHJdKGh0dHBzOi8vcmVhZHIudGlkeXZlcnNlLm9yZy9hcnRpY2xlcy9yZWFkci5odG1sKQ0KUiBwYWNrYWdlLiBUaGUgbWFpbiByZWFzb25zIGZvciB0aGlzIGFyZSANCg0KMS4gQ29tcGFyZWQgdG8gZXF1aXZhbGVudCBiYXNlIFIgZnVuY3Rpb25zLCB0aGUgDQpmdW5jdGlvbnMgaW4gYHJlYWRyYCBhcmUgYXJvdW5kIDEweCBmYXN0ZXIuIA0KMi4gWW91IGNhbiBzcGVjaWZ5IHRoZSBjb2x1bW4gdHlwZXMgKGUuZyANCmNoYXJhY3RlciwgaW50ZWdlciwgZG91YmxlLCBsb2dpY2FsLCBkYXRlLCANCnRpbWUsIGV0YykNCjMuIEFsbCBwYXJzaW5nIHByb2JsZW1zIGFyZSByZWNvcmRlZCBpbiANCmEgZGF0YSBmcmFtZS4gDQogICAgICAgICAgDQoNClRoZSBtYWluIGZ1bmN0aW9ucyBpbiBgcmVhZHJgIGluY2x1ZGU6IA0KDQpgcmVhZHJgIGZ1bmN0aW9ucyB8IERlc2NyaXB0aW9uIHwNCi0tLSB8IC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gfA0KYHJlYWRfZGVsaW0oKWAgfCByZWFkcyBpbiBhIGZsYXQgZmlsZSBkYXRhIHdpdGggYSBnaXZlbiBjaGFyYWN0ZXIgdG8gc2VwYXJhdGUgZmllbGRzIHwNCmByZWFkX2NzdigpYCB8IHJlYWRzIGluIGEgQ1NWIGZpbGUgfA0KYHJlYWRfdHN2KClgIHwgcmVhZHMgaW4gYSBmaWxlIHdpdGggdmFsdWVzIHNlcGFyYXRlZCBieSB0YWJzIHwNCmByZWFkX2xpbmVzKClgIHwgcmVhZHMgb25seSBhIGNlcnRhaW4gbnVtYmVyIG9mIGxpbmVzIGZyb20gdGhlIGZpbGUgfA0KYHJlYWRfZmlsZSgpYCB8IHJlYWRzIGEgY29tcGxldGUgZmlsZSBpbnRvIGEgc3RyaW5nIHwNCmB3cml0ZV9jc3YoKWAgfCB3cml0ZXMgZGF0YSBmcmFtZSB0byBDU1YgfCANCg0KQSB1c2VmdWwgY2hlYXRzaGVldCBmb3IgdGhlIGZ1bmN0aW9ucyBpbiB0aGUNCmByZWFkcmAgcGFja2FnZSBjYW4gYmUgZm91bmQgb24gUlN0dWRpbydzIHdlYnNpdGU6IA0KDQohW10oaHR0cHM6Ly93d3cucnN0dWRpby5jb20vd3AtY29udGVudC91cGxvYWRzLzIwMTgvMDgvZGF0YS1pbXBvcnQucG5nKQ0KICAgICANCmBgYHtyfQ0KbGlicmFyeShyZWFkcikNCnByZXNjcmlwdGlvbl8yMDE2IDwtIHJlYWRfY3N2KCIuL2RhdGEvMjAxNnByZXNjcmliZXIuY3N2IikNCnByZXNjcmlwdGlvbl8yMDE1IDwtIHJlYWRfY3N2KCIuL2RhdGEvMjAxNXByZXNjcmliZXIuY3N2IikNCnByZXNjcmlwdGlvbl8yMDE0IDwtIHJlYWRfY3N2KCIuL2RhdGEvMjAxNHByZXNjcmliZXIuY3N2IikNCnByZXNjcmlwdGlvbl8yMDEzIDwtIHJlYWRfY3N2KCIuL2RhdGEvMjAxM3ByZXNjcmliZXIuY3N2IikNCmBgYA0KDQojIERhdGEgV3JhbmdsaW5nICANCkNvbWJpbmluZyB0aGUgZnVuY3Rpb25zIGluIHRoZSBwYWNrYWdlcyBgZHBseXJgIGFuZCANCmBrYWJsZUV4dHJhYCBjYW4gaGVscCB1cyB0YWtlIGEgZ2xhbmNlIGF0IHRoZSBkYXRhLiANCkhlcmUsIHdlIHVzZSB0aGUgYG11dGF0ZWAgdG8gZ2VuZXJhdGUgYSBuZXcgY2hhcmFjdGVyIA0KdmFyaWFibGUgbmFtZWQgYE5QSWAgYW5kIHVzZSB0aGUgYGthYmxlKClgIGFuZCANCmBrYWJsZV9zdHlsaW5nYCB0byBtYWtlIHRoZSBkaXNwbGF5IGNsZWFyZXIuICAgDQpgYGB7cn0NCnByZXNjcmlwdGlvbl8yMDE2ICU+JSANCiAgbXV0YXRlKE5QSSA9IGFzLmNoYXJhY3RlcihOUEkpKSAlPiUgDQogIGhlYWQoLikgJT4lDQogIGthYmxlKCkgJT4lDQogIGthYmxlX3N0eWxpbmcoKQ0KYGBgDQpXZSBjYW4gc2VlIHRoYXQgdGhlIGRhdGEgaXMgc3RydWN0dXJlZCBhcyBwcm92aWRlci1iYXNlZCBsZXZlbCwgDQptZWFuaW5nIHRoYXQgdGhlIGluZm9ybWF0aW9uIGluIGVhY2ggcm9sZSBpcyBmb3IgdGhlIHNwZWNpZmljIA0KaGVhbHRoIGNhcmUgcHJvdmlkZXIuIEluIHRoaXMgcHJvamVjdCwgd2UncmUgZ29pbmcgdG8gZG8gdGhlIA0KYW5hbHlzaXMgYXQgU3RhdGUgbGV2ZWwsIHNvIHlvdSBjYW4gcHJvYmFibHkgaW1hZ2luZSB0aGF0IHdlIA0KbmVlZCB0byBoYXZlIHNvbWUgcHJvY2VzcyB0byBnZXQgU3RhdGUtbGV2ZWwgaW5mb3JtYXRpb24gZnJvbSANCnRoaXMgZGF0YS4gQmVmb3JlIG1vdmluZyB0aGVyZSwgbGV0J3MgdGFrZSBhIGxvb2sgYXQgDQpob3cgYmlnIHRoZSBkYXRhIGlzIGZvciB0aGUgMjAxNiBpbmZvcm1hdGlvbjogDQpgYGB7cn0NCmRpbShwcmVzY3JpcHRpb25fMjAxNikNCmBgYA0KV293ISBUaGVyZSBhcmUgYHIgbnJvdyhwcmVzY3JpcHRpb25fMjAxNilgIGhlYWx0aCBwcm92aWRlcnMgDQpsaXN0ZWQgaW4gdGhpcyBmaWxlLiBPZiBub3RlLCBub3QgZXZlcnkgaGVhbHRoIHByb3ZpZGVyIGhhZCANCnByZXNjcmliZWQgb3Bpb2lkIGluIHRoZSB5ZWFyIDIwMTYuICAgIA0KDQojIyAxLiBBZGQgU3RhdGUgaW5mb3JtYXRpb24gICANCkluIG1hbnkgY2FzZXMsIHdlIHdhbnQgdG8gYWRkIGJhc2ljIGluZm9ybWF0aW9uIGFib3V0IFN0YXRlcywgDQpzdWNoIGFzIFN0YXRlIG5hbWUsIFJlZ2lvbiwgYW5kIFN0YXRlIGFiYnJldmlhdGlvbiANCmluIG91ciBkYXRhc2V0LiBXZSBjYW4gZ2V0IHRoaXMgaW5mb3JtYXRpb24gZWFzaWx5IHVzaW5nIA0KdGhlIGRhdGFzZXQgYHN0YXRlYCBpbiB0aGUgbGlicmFyeSBgZGF0YXNldHNgLiBIb3dldmVyLCANCmJlZm9yZSB0YWtpbmcgYWR2YW50YWdlIG9mIHRoZSBgc3RhdGVgLCB3ZSBuZWVkIHRvIHRha2UgYSBsb29rIA0KYXQgb3VyIGRhdGEsIGFuZCBoYXZlIGFuIGlkZWEgYWJvdXQgd2hldGhlciB3ZSBjYW4gYWRvcHQgDQp0aGUgaW5mb3JtYXRpb24gaW4gYHN0YXRlYCBkaXJlY3RseS4gIA0KIyMjIyBIb3cgbWFueSBTdGF0ZXMgYXJlIHRoZXJlIGluIHRoZSAyMDE2IHByZXNjcmlwdGlvbiBkYXRhc2V0Pw0KYGBge3J9DQp1bmlxdWUocHJlc2NyaXB0aW9uXzIwMTYkYE5QUEVTIFByb3ZpZGVyIFN0YXRlYCkNCmBgYA0KDQpUaGVyZSBhcmUgNjEgdmFsdWVzIGZvciBgTlBQRVMgUHJvdmlkZXIgU3RhdGVgLiANCkZyb20gdGhlIFttYW51YWxdKGh0dHBzOi8vd3d3LmNtcy5nb3YvUmVzZWFyY2gtU3RhdGlzdGljcy1EYXRhLWFuZC1TeXN0ZW1zL1N0YXRpc3RpY3MtVHJlbmRzLWFuZC1SZXBvcnRzL01lZGljYXJlLVByb3ZpZGVyLUNoYXJnZS1EYXRhL0Rvd25sb2Fkcy9QcmVzY3JpYmVyX01ldGhvZHMucGRmKSwgDQp3ZSBrbm93IHRoYXQgb3RoZXIgdGhhbiB0aGUgZmlmdHkgU3RhdGVzIGFuZCBEQywgdGhlcmUgYXJlIA0KdGhlIG90aGVyIDEwIHZhbHVlcyBhcyBmb2xsb3dpbmc6DQoNClZhbHVlcyBmb3IgYE5QUEVTIFByb3ZpZGVyIFN0YXRlYCB8ICBEZXNjcmlwdGlvbiAgfA0KLS0tIHwgLS0tIHwNCmBYWGAgfCBVbmtub3duIHwNCmBBQWAgfCBBcm1lZCBGb3JjZXMgQ2VudHJhbC9Tb3V0aCBBbWVyaWNhIHwNCmBBRWAgfCBBcm1lZCBGb3JjZXMgRXVyb3BlIHwNCmBBUGAgfCBBcm1lZCBGb3JjZXMgUGFjaWZpYyB8DQpgQVNgIHwgQW1lcmljYW4gU2Ftb2EgfA0KYEdVYCB8IEd1YW0gfA0KYE1QYCB8IE5vcnRoZXJuIE1hcmlhbmEgSXNsYW5kcyB8DQpgUFJgIHwgUHVlcnRvIFJpY28gfA0KYFZJYCB8IFZpcmdpbiBJc2xhbmRzIHwNCmBaWmAgfCBGb3JlaWduIENvdW50cnkgfA0KICAgIA0KIyMjIyBBZGQgdGhlIGluZm9ybWF0aW9uIChTdGF0ZSBuYW1lLCByZWdpb24sIGFuZCBhYmJyZXZpYXRpb24pIHRvIHRoZSBgc3RhdGVgIGluIHRoZSBgZGF0YXNldHNgICAgDQpgYGB7cn0NCmxpYnJhcnkoZGF0YXNldHMpDQpkYXRhKHN0YXRlKQ0KdW5pcXVlKHN0YXRlLm5hbWUpICMgVGhlcmUgYXJlIG9ubHkgNTAgU3RhdGVzDQpzdGF0ZS5hYmIgPC0gYyhzdGF0ZS5hYmIsICJEQyIsDQogICAgICAgICAgICAgICAiWFgiLA0KICAgICAgICAgICAgICAgIkFBIiwNCiAgICAgICAgICAgICAgICJBRSIsDQogICAgICAgICAgICAgICAiQVAiLA0KICAgICAgICAgICAgICAgIkFTIiwNCiAgICAgICAgICAgICAgICJHVSIsDQogICAgICAgICAgICAgICAiTVAiLA0KICAgICAgICAgICAgICAgIlBSIiwNCiAgICAgICAgICAgICAgICJWSSIsDQogICAgICAgICAgICAgICAiWloiKQ0Kc3RhdGUucmVnaW9uIDwtIGFzLmZhY3RvcihjKGFzLmNoYXJhY3RlcihzdGF0ZS5yZWdpb24pLCAiU291dGgiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlcCgiT3RoZXJzIiwxMCkpKQ0Kc3RhdGUubmFtZSA8LSBjKHN0YXRlLm5hbWUsICJEaXN0cmljdCBvZiBDb2x1bWJpYSIsDQogICAgICAgICAgICAgICAgIlVua25vd24iLA0KICAgICAgICAgICAgICAgICJBcm1lZCBGb3JjZXMgQ2VudHJhbC9Tb3V0aCBBbWVyaWNhIiwNCiAgICAgICAgICAgICAgICAiQXJtZWQgRm9yY2VzIEV1cm9wZSIsDQogICAgICAgICAgICAgICAgIkFybWVkIEZvcmNlcyBQYWNpZmljIiwNCiAgICAgICAgICAgICAgICAiQW1lcmljYW4gU2Ftb2EiLA0KICAgICAgICAgICAgICAgICJHdWFtIiwNCiAgICAgICAgICAgICAgICAiTm9ydGhlcm4gTWFyaWFuYSBJc2xhbmRzIiwNCiAgICAgICAgICAgICAgICAiUHVlcnRvIFJpY28iLA0KICAgICAgICAgICAgICAgICJWaXJnaW4gSXNsYW5kcyIsDQogICAgICAgICAgICAgICAgIkZvcmVpZ24gQ291bnRyeSIpDQoNCnN0YXRlcyA8LSB1bmlxdWUocHJlc2NyaXB0aW9uXzIwMTYkYE5QUEVTIFByb3ZpZGVyIFN0YXRlYCkgJT4lIGRhdGEuZnJhbWUoLikNCm5hbWVzKHN0YXRlcykgPC0gIk5QUEVTIFByb3ZpZGVyIFN0YXRlIg0Kc3RhdGVzJHN0YXRlX25hbWUgPC0gc3RhdGUubmFtZVttYXRjaCh0b2xvd2VyKHN0YXRlcyRgTlBQRVMgUHJvdmlkZXIgU3RhdGVgKSwgdG9sb3dlcihzdGF0ZS5hYmIpKV0NCnN0YXRlcyRyZWdpb24gPC0gc3RhdGUucmVnaW9uW21hdGNoKHRvbG93ZXIoc3RhdGVzJGBOUFBFUyBQcm92aWRlciBTdGF0ZWApLCB0b2xvd2VyKHN0YXRlLmFiYikpXQ0KDQpzdGF0ZXMgJT4lICANCiAga2FibGUoKSAlPiUNCiAga2FibGVfc3R5bGluZygpIA0KYGBgDQoNCiMjIDIuIEFkZCBwb3B1bGF0aW9uIGluZm9ybWF0aW9uIGZvciBlYWNoIFN0YXRlICANClNpbmNlIGl0JyByZWFzb25hYmxlIHRvIGhhdmUgbW9yZSBvcGlvaWQgY2xhaW1zIHNpbXBseSANCmR1ZSB0byBtb3JlIHBhcnRpY2lwYW50cyBlbnJvbGxlZCBpbiB0aGUgUGFydCBELCANCndlIG1heSB3YW50IHRvIGNvbXBhcmUgdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcGVyIDEwMCANCmVucm9sbG1lbnRzIGluc3RlYWQgb2YgdG90YWwgbnVtYmVyIG9mIG9waW9pZCBwcmVzY3JpcHRpb25zIA0KYWNyb3NzIFN0YXRlcy4gVGh1cywgb25lIG9mIHRoZSBxdWVzdGlvbnMgd2UgYXJlIGludGVyZXN0ZWQgaW4gDQppcyB3aGF0J3MgdGhlIGRpc3RyaWJ1dGlvbiBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uIHBlciANCjEwMCBlbnJvbGxtZW50cyBieSBTdGF0ZXMuIFRvIGFuc3dlciBvdXIgcXVlc3Rpb24sIA0Kb3RoZXIgdGhhbiB0aGUgb3Bpb2lkIGNsYWltIGluZm9ybWF0aW9uIHdlJ3ZlIGFscmVhZHkgZ290LCANCndlIGFsc28gbmVlZCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgaG93IG1hbnkgcGFydGljaXBhbnRzIA0KZW5yb2xsZWQgaW4gdGhlIFBhcnQgRCBwbGFuIGZvciBlYWNoIFN0YXRlLiBUbyB0aGUgYmVzdCBvZiANCm91ciBrbm93bGVkZ2UsIHdlIGNhbiBnZXQgdGhlIDIwMTUgZW5yb2xsbWVudCBpbmZvcm1hdGlvbiBmcm9tIA0KdGhlIHB1YmxpY2x5IGF2YWlsYWJsZSANCltDTVMgd2Vic2l0ZV0oaHR0cHM6Ly93d3cuY21zLmdvdi9uZXdzcm9vbS9wcmVzcy1yZWxlYXNlcy9pdHMtNTB0aC1hbm5pdmVyc2FyeS1tb3JlLTU1LW1pbGxpb24tYW1lcmljYW5zLWNvdmVyZWQtbWVkaWNhcmUpLiAgICANCihOb3RlOiBUaGUgaW5mb3JtYXRpb24gaXMgYmFzZWQgb24gMjAxNS4gDQpQbGVhc2UgbGV0IHVzIGtub3cgaWYgdGhlcmUgYXJlIHllYXItYnkteWVhciANClN0YXRlLWxldmVsIFBhcnQgRCBlbnJvbGxtZW50IGluZm9ybWF0aW9uLCANCnNvIHRoYXQgd2UgY2FuIHVwZGF0ZSB0aGlzIGFuYWx5c2lzLikNCmBgYHtyfQ0KcG9wdWxhdGlvbiA8LSByZWFkX2NzdigiLi9kb2MyL2Vucm9sbG51bWJlci5jc3YiKSAlPiUNCiAgICAgICAgICAgICAgICByZW5hbWUoIHN0YXRlX25hbWUgPSBTdGF0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGVucm9sbG1lbnRfbnVtMjAxNSA9IFRvdGFsKQ0KYGBgDQpOb3csIHdlIGNhbiBhZGQgdGhlIG51bWJlciBvZiBlbnJvbGxtZW50cyBpbiANClBhcnQgRCBieSBTdGF0ZSBmcm9tIGBwb3B1bGF0aW9uYCB0byB0aGUgDQpTdGF0ZXMgaW5mb3JtYXRpb24gZGF0YXNldCBgc3RhdGVzYC4gICANCk5vdGUgdGhhdCB0aGVyZSBpcyBzb21lIGRpZmZlcmVuY2UgaW4gdGhlIA0KbmFtZXMgb2YgU3RhdGVzIGJldHdlZW4gYHBvcHVsYXRpb25gIGFuZCANCmBzdGF0ZXNgLiBUaGV5IGFyZSAiUGVuZGluZyBTdGF0ZSBEZXNpZ25hdGlvbiIgDQphbmQgIkZvcmVpZ24gYW5kIE90aGVyIE91dGx5aW5nIEFyZWFzIi4gVGh1cywgDQppbiB0aGUgZnVydGhlciBhbmFseXNpcywgd2UgY2FuIGNvbnNpZGVyIGlmIHdlIA0Kd2FudCB0byBhZGQgdGhlbSBpbiBvciBleGNsdWRlIHRoZW0uIA0KYGBge3J9DQpwb3B1bGF0aW9uJHN0YXRlX25hbWUNCmBgYA0KTm93LCB3ZSBjYW4gY29tYmluZSB0aGUgcG9wdWxhdGlvbiBpbmZvcm1hdGlvbiB3aXRoIA0KdGhlIGBzdGF0ZWAsIGFuZCBzYXZlIGl0IGFzIGEgbmV3IGRhdGEgZnJhbWUgY2FsbGVkIA0KYHBvcHVsYXRpb25zdGF0ZWANCmBgYHtyfQ0KcG9wdWxhdGlvbnN0YXRlIDwtIHN0YXRlcyAlPiUgDQogICAgICAgICAgICAgICAgICAgICAgbGVmdF9qb2luKC4scG9wdWxhdGlvbiwgYnkgPSBjKCJzdGF0ZV9uYW1lIikpDQpgYGANCkxldCdzIHNlZSB3aGF0IHRoZSBgcG9wdWxhdGlvbnN0YXRlYCBsb29rcyBsaWtlLiANCmBgYHtyfQ0KcG9wdWxhdGlvbnN0YXRlICU+JQ0KICBoZWFkKCkgJT4lIA0KICBrYWJsZSgpICU+JSANCiAga2FibGVfc3R5bGluZygpIA0KYGBgDQojIyMjIENhbiB5b3UgdGVsbCBob3cgbWFueSBTdGF0ZXMgZG8gd2UgaGF2ZSB0aGUgaW5mb3JtYXRpb24gYWJvdXQgbnVtYmVyIG9mIGVucm9sbG1lbnRzIGluIFBhcnQgRCA/IA0KYGBge3J9DQpzdW0oIWlzLm5hKHBvcHVsYXRpb25zdGF0ZSRlbnJvbGxtZW50X251bTIwMTUpKSAgDQpgYGANCg0KIyMgMy4gR2xpbXBzZSBhdCBvcGlvaWQgaW5mb3JtYXRpb24gDQpJbiB0aGUgZGF0YXNldCBgcHJlc2NyaXB0aW9uXzIwMTZgLCB3ZSBoYXZlIGluZm9ybWF0aW9uIGFib3V0IA0KdG90YWwgY2xhaW0gY291bnQsIG9waW9pZCBjbGFpbSBjb3VudCwgYW5kIGV4dGVuZGVkLXJlbGVhc2Ugb3Bpb2lkIA0KY2xhaW1zLiBGb3IgdGhpcyBwcm9qZWN0LCB3ZSBvbmx5IG5lZWQgdG8gbG9vayBhdCBvcGlvaWQgY2xhaW0gY291bnQgYW5kIA0KdG90YWwgY2xhaW0gY291bnQuIA0KYGBge3J9DQpzdW0oaXMubmEocHJlc2NyaXB0aW9uXzIwMTYkYFRvdGFsIENsYWltIENvdW50YCkpDQpzdW0oaXMubmEocHJlc2NyaXB0aW9uXzIwMTYkYE9waW9pZCBDbGFpbSBDb3VudGApKQ0KYGBgDQpXZSBub3RpY2VkIHRoYXQgdGhlcmUgYXJlIHNvbWUgbWlzc2luZyB2YWx1ZXMgZHVlIGluIGBPcGlvaWQgQ2xhaW0gQ291bnRgLiANClRoaXMgdGVsbHMgdXMgdGhhdCBub3QgZXZlcnkgcHJvdmlkZXIgaW5jbHVkZWQgaW4gdGhpcyBkYXRhc2V0IA0KaXMgZWxpZ2libGUgdG8gcHJlc2NyaWJlIG9waW9pZC4gVGh1cywgaW4gdGhlIG5leHQgc3RlcCwgd2hlbiB3ZSANCndhbnQgdG8gY2FsY3VsYXRlIHRoZSBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgYnkgU3RhdGUsIHdlIG5lZWQgdG8gbGltaXQgb3VyIA0KZGF0YSB0byB0aG9zZSBwcm92aWRlcnMgd2l0aCBib3RoIHRvdGFsIGNsYWltIGluZm9ybWF0aW9uIGFuZCANCm9waW9pZCBjbGFpbSBpbmZvcm1hdGlvbi4gDQogIA0KIyMgNC4gQ2FsY3VsYXRlIHRoZSBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgIA0KR3JlYXQhIE5vdyB3ZSBoYXZlIGJldHRlciBpZGVhIGFib3V0IG91ciBkYXRhc2V0LCBhbmQgDQp3ZSBuZWVkIHRvIGNyZWF0ZSBhIGRhdGFzZXQgY29udGFpbmluZyB0aGUgaW5mb3JtYXRpb24gDQp3ZSBuZWVkIHRvIGFuc3dlciBvdXIgcXVlc3Rpb25zLiBJbiBvdGhlciB3b3Jkcywgd2UgDQp3YW50IHRvIGNyZWF0ZSBhIGRhdGFzZXQgZm9yIGVhY2ggeWVhciB3aXRoIGZvbGxvd2luZyANCmluZm9ybWF0aW9uOiAgICANCiAgIA0KVmFyaWFibGUgTmFtZSB8ICBEZXNjcmlwdGlvbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCi0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwNCk5QUEVTIFByb3ZpZGVyIFN0YXRlIHwgU3RhdGUgQWJicmV2aWF0aW9uIHwNCnRvdGFsX29waW9pZF9jbGFpbSB8IFRvdGFsIG9waW9pZCBjbGFpbXMgKFBhcnQgRCkgaW4gdGhlIFN0YXRlIHwNCnRvdGFsX2NsYWltX2NvdW50IHwgVG90YWwgY2xhaW1zIChQYXJ0IEQpIGluIHRoZSBTdGF0ZSB8DQpzdGF0ZV9vcGlvaWRfcHJlc2NyaWJpbmdfcmF0ZSB8IFRoZSBwcm9wb3J0aW9uIG9mIHRvdGFsIG9waW9pZCBjbGFpbXMgdmVyc3VzIHRvdGFsIGNsYWltcyAoUGFydCBEKSBpbiB0aGUgU3RhdGUgfA0Kc3RhdGVfbmFtZSB8IFN0YXRlIE5hbWUgfA0KcmVnaW9uIHwgVGhlIHJlZ2lvbiBvZiB0aGUgU3RhdGUgfA0KZW5yb2xsbWVudF9udW0yMDE1IHwgTnVtYmVyIG9mIFBhcnQgRCBlbnJvbGxtZW50cyBpbiAyMDE1IHwNCnRvdGFsX2NsYWltX2J5cG9wIHwgVG90YWwgY2xhaW1zIHBlciAxMDAgZW5yb2xsbWVudCAoKikgfA0Kb3Bpb2lkX2NsYWltX2J5cG9wIHwgT3Bpb2lkIGNsYWltcyBwZXIgMTAwIGVucm9sbG1lbnQgKCopIHwNCnllYXIgfCB5ZWFyIG9mIHRoZSBkYXRhIGNhbWUgZnJvbSB8ICANCigqKSBUaGVzZSBudW1iZXJzIGFyZSB2YWxpZCBvbmx5IGZvciB5ZWFyIDIwMTUuDQoNClNpbmNlIHdlJ3JlIGdvaW5nIHRvIHVzZSB0aGUgc2FtZSBjaHVjayBvZiBjb2RlcyBtYW55IA0KdGltZXMsIHdlIGNhbiB3cml0ZSBhIGZ1bmN0aW9uIG5hbWVkIGBhbmFkYXRhYCB0byBzYXZlIG91ciB0aW1lcyEgICANCmBgYHtyfQ0KYW5hZGF0YSA8LSBmdW5jdGlvbihkYXRhID0gZGF0YSwgeWVhciA9IHllYXIpew0KICBjIDwtIHllYXINCiAgZGF0YSAlPiUgDQogICAgbGVmdF9qb2luKC4scG9wdWxhdGlvbnN0YXRlLGJ5ID0gYygiTlBQRVMgUHJvdmlkZXIgU3RhdGUiKSkgJT4lDQogICAgc2VsZWN0KGBOUFBFUyBQcm92aWRlciBTdGF0ZWAsDQogICAgICAgICAgIHN0YXRlX25hbWUscmVnaW9uLA0KICAgICAgICAgICBgT3Bpb2lkIENsYWltIENvdW50YCwNCiAgICAgICAgICAgYFRvdGFsIENsYWltIENvdW50YCkgJT4lIA0KICAgIGZpbHRlcihpcy5uYShgVG90YWwgQ2xhaW0gQ291bnRgKSArIA0KICAgICAgICAgICBpcy5uYShgT3Bpb2lkIENsYWltIENvdW50YCkgPT0gMCApICU+JQ0KICAgIGdyb3VwX2J5KGBOUFBFUyBQcm92aWRlciBTdGF0ZWApICU+JSANCiAgICBzdW1tYXJpc2UodG90YWxfb3Bpb2lkX2NsYWltID0gc3VtKGBPcGlvaWQgQ2xhaW0gQ291bnRgKSwNCiAgICAgICAgICAgICAgdG90YWxfY2xhaW1fY291bnQgPSBzdW0oYFRvdGFsIENsYWltIENvdW50YCkpICU+JSANCiAgICBtdXRhdGUoc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUgPSANCiAgICAgICAgICAgKHRvdGFsX29waW9pZF9jbGFpbS90b3RhbF9jbGFpbV9jb3VudCkqMTAwKSAlPiUNCiAgICBhcnJhbmdlKGRlc2Moc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUpKSAlPiUNCiAgICBsZWZ0X2pvaW4oLixwb3B1bGF0aW9uc3RhdGUsYnkgPSBjKCJOUFBFUyBQcm92aWRlciBTdGF0ZSIpKSAlPiUNCiAgICBtdXRhdGUodG90YWxfY2xhaW1fYnlwb3AgPSANCiAgICAgICAgICAgKHRvdGFsX2NsYWltX2NvdW50L2Vucm9sbG1lbnRfbnVtMjAxNSkqMTAwLA0KICAgICAgICAgICBvcGlvaWRfY2xhaW1fYnlwb3AgPSANCiAgICAgICAgICAgKHRvdGFsX29waW9pZF9jbGFpbS9lbnJvbGxtZW50X251bTIwMTUpKjEwMCkgJT4lDQogICAgZmlsdGVyKCFpcy5uYShzdGF0ZS5uYW1lKSkgJT4lDQogICAgbXV0YXRlKHllYXIgPSBjKSAtPiB4Ow0KICAgIG5hbWVzKHgpID0gdG9sb3dlcihuYW1lcyh4KSk7ICMgV2UgY2hhbmdlIHRoZSB2YXJpYWJsZSBuYW1lcyB0byBsb3dlcmNhc2UuDQogIHJldHVybih4KQ0KIH0gDQoNCnByZXNjcmliZXIyMDE2YnlTdGF0ZSA8LSBhbmFkYXRhKHByZXNjcmlwdGlvbl8yMDE2LDIwMTYpDQpwcmVzY3JpYmVyMjAxNWJ5U3RhdGUgPC0gYW5hZGF0YShwcmVzY3JpcHRpb25fMjAxNSwyMDE1KQ0KcHJlc2NyaWJlcjIwMTRieVN0YXRlIDwtIGFuYWRhdGEocHJlc2NyaXB0aW9uXzIwMTQsMjAxNCkNCnByZXNjcmliZXIyMDEzYnlTdGF0ZSA8LSBhbmFkYXRhKHByZXNjcmlwdGlvbl8yMDEzLDIwMTMpDQpgYGANCiAgICAgDQpIZXJlLCB3ZSB3cml0ZSBhIGxvb3AgdG8gZXhlY3V0ZSB0aGUgcmVwZXRpdGl2ZSBwcm9jZWR1cmVzLiANClRoZSBhbHRlcm5hdGl2ZSB0byBkbyBpdCBpcyB0byBpbXBsZW1lbnQgc29tZSBjb21tYW5kcyBpbiANCnRoZSBwYWNrYWdlIGBwdXJycmAuIFsgSGVyZSBpcyB0aGUgY2hlYXRzaGVldCBmb3IgDQp1c2luZyBbcHVycnJdKGh0dHBzOi8vZ2l0aHViLmNvbS9yc3R1ZGlvL2NoZWF0c2hlZXRzL3Jhdy9tYXN0ZXIvcHVycnIucGRmKV0gICAgDQoNCk5vdywgd2UncmUgcmVhZHkgZm9yIG91ciBuZXh0IHN0ZXAgLSBkYXRhIHZpc3VhbGl6YXRpb24hIA0KDQojIERhdGEgVmlzdWFsaXphdGlvbiAgDQojIyAxLiBDb21wYXJpbmcgdG90YWwgb3Bpb2lkIHByZXNjcmlwdGlvbnMgaW4gMjAxNiAgIA0KVGhlIGZpcnN0IHRhc2sgaXMgdG8gdW5kZXJzdGFuZCB0aGUgb3Bpb2lkIHByZXNjcmlwdGlvbnMgYnkgU3RhdGVzIGluIDIwMTYuIA0KV2UgYXJlIGdvaW5nIHRvIHVzZSB0aGUgZnVuY3Rpb25zIGluIHRoZSBsaWJyYXJ5IGBnZ3Bsb3QyYCB0byBoZWxwIHVzIA0KcGxvdCB0aGUgYmFyIGNoYXJ0LiAgIA0KYGBge3IgZmlnLndpZHRoPTgsZmlnLmhlaWdodD0xMH0NCmxpYnJhcnkoZ2dwbG90MikNCnAgPC0gcHJlc2NyaWJlcjIwMTZieVN0YXRlICU+JSANCiAgICAgICAgICAgICAgICAgICAgZ2dwbG90KGFlcyh4PXJlb3JkZXIoc3RhdGVfbmFtZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLXRvdGFsX29waW9pZF9jbGFpbSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHk9dG90YWxfb3Bpb2lkX2NsYWltKSkgKyANCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKQ0KDQpwICsgdGhlbWVfYncoKSArIA0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwgDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxLHZqdXN0ID0gMC41KSkgKyANCiAgICBnZ3RpdGxlKCJUb3RhbCBvcGlvaWQgY2xhaW1zIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIGluIDIwMTYiKSArIA0KICAgIHhsYWIoIlN0YXRlcyIpICsgDQogICAgeWxhYigiTnVtYmVyIG9mIG9waW9pZCBjbGFpbXMiKSANCmBgYCAgICAgICANCiAgICAgICAgIA0KSXQncyBuaWNlIHRvIHZpc3VhbGl6ZSBhbGwgdGhlIGluZm9ybWF0aW9uIHdlIGhhdmUgZnJvbSB0aGlzIGRhdGFzZXQuIEhvd2V2ZXIsIA0KYmFzZWQgb24gb3VyIG9yaWdpbmFsIHF1ZXN0aW9ucywgd2UgbWF5IHdhbnQgdG8gZm9jdXMgb24gdGhlIDUwIFN0YXRlcyBhbmQgDQpEQy4gU2luY2UgZm9yIGFsbCB0aGUgcmVnaW9ucyBvdGhlciB0aGFuIHRoZSA1MCBTdGF0ZXMgYW5kIERDLCB0aGV5IHdlcmUgDQpsYWJlbGxlZCBhcyBgT3RoZXJzYCBpbiB0aGVpciBgcmVnaW9uYCB2YXJpYWJsZSwgd2UgY2FuIGxpbWl0IHRoZSBhbmFseXNpcyANCmJhc2VkIG9uIHRoZW0gdXNpbmcgdGhlICoqZmlsdGVyKiogLiAgICAgDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTEwfQ0KcCA8LSBwcmVzY3JpYmVyMjAxNmJ5U3RhdGUgJT4lIA0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocmVnaW9uIT0iT3RoZXJzIikgJT4lDQogICAgICAgICAgICAgICAgICAgIGdncGxvdChhZXMoeD1yZW9yZGVyKHN0YXRlX25hbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC10b3RhbF9vcGlvaWRfY2xhaW0pLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PXRvdGFsX29waW9pZF9jbGFpbSkpICsgDQogICAgICAgICAgICAgICAgICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikNCg0KcCArIHRoZW1lX2J3KCkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksIA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSx2anVzdCA9IDAuNSkpICsgDQogICAgZ2d0aXRsZSgiVG90YWwgb3Bpb2lkIGNsYWltcyAoaW4gTWVkaWNhcmUgUGFydCBEKSBieSBTdGF0ZSBpbiAyMDE2IikgKyANCiAgICB4bGFiKCJTdGF0ZXMiKSArIA0KICAgIHlsYWIoIk51bWJlciBvZiBvcGlvaWQgY2xhaW1zIikgDQpgYGAgICANCiAgICANCiAgICAgDQpZb3UgbWF5IHdvbmRlciB3aHkgdGhlIGxhYmVscyBvbiB0aGUgeS1heGlzIGFyZSAqKjZlKzA2KiogLCAqKjRlKzA2KiogLCANCi4uLiwgd2hpY2ggYXJlIHJlbGF0aXZlbHkgaGFyZCB0byByZWFkLiBIZXJlIGNvbWVzIG9uZSBwb3RlbnRpYWwgc29sdXRpb24gLSANCnVzaW5nIHRoZSAqKnNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkqKiBpbiB0aGUgbGlicmFyeSBgc2NhbGVzYC4gDQpUaGlzIGZ1bmN0aW9uIHdpbGwgZm9yY2UgdGhlIGRpc3BsYXkgb2YgbGFiZWxzIGluIHktYXhpcyBiZSBhbiBlYXN5LXRvLXJlYWQgDQpudW1iZXIuICAgDQoNCmBgYHtyIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9MTB9DQpsaWJyYXJ5KHNjYWxlcykNCnAgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsNCiAgICB0aGVtZV9idygpICsgDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSApLCANCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEsdmp1c3QgPSAwLjUpKSArIA0KICAgIGdndGl0bGUoIlRvdGFsIG9waW9pZCBjbGFpbXMgKGluIE1lZGljYXJlIFBhcnQgRCkgYnkgU3RhdGUgaW4gMjAxNiIpICsgDQogICAgeGxhYigiU3RhdGVzIikgKyANCiAgICB5bGFiKCJOdW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyIpIA0KYGBgDQogICAgICAgICANCllvdSBtYXkgZmVlbCBpdCdzIGhhcmQgdG8gcmVhZCBzaW5jZSB5b3UgbmVlZCB0byBlaXRoZXIgDQp0aWx0IHlvdXIgaGVhZCBvciBoYXZlIGEgc3BlY2lhbCBhYmlsaXR5IHRvIHJlYWQgdGhlIGxhYmVscyBvZiBTdGF0ZXMgaW4gdGhlIA0KeC1heGlzLiBIZXJlLCB3ZSBwcm92aWRlIG9uZSB3YXkgdG8gcm90YXRlIHRoaXMgYmFyIGNoYXJ0IA0KdXNpbmcgKipjb29yZF9mbGlwKCkqKiAuDQogICAgICAgICAgIA0KYGBge3IgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9OH0NCnAgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsgDQogICAgY29vcmRfZmxpcCgpICsNCiAgICB0aGVtZV9idygpICsgDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSApLCANCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSx2anVzdCA9IDAuNSkpICsgIA0KICAgIGdndGl0bGUoIlRvdGFsIG9waW9pZCBjbGFpbXMgKGluIE1lZGljYXJlIFBhcnQgRCkgYnkgU3RhdGUgaW4gMjAxNiIpICsgDQogICAgeGxhYigiU3RhdGVzIikgKyANCiAgICB5bGFiKCJOdW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyIpIA0KYGBgICAgICANCiAgICAgDQojIyMgKDEpIFdoYXQgYXJlIHRoZSB0b3AgZml2ZSBTdGF0ZXMgd2l0aCB0aGUgaGlnaGVzdCBhbmQgbG93ZXN0IG9waW9pZCBwcmVzY3JpcHRpb24gY2xhaW1zIGluIFBhcnQgRCBpbiAyMDE2PyAgIA0KQmFzZWQgb24gdGhlIHBsb3QgYWJvdmUsIENhbGlmb3JuaWEsIEZsb3JpZGEsIFRleGFzLCBQZW5uc3lsdmFuaWEsIA0KYW5kIE1pY2hpZ2FuIGFyZSB0aGUgdG9wIGZpdmUgU3RhdGVzIHdpdGggdGhlIGhpZ2hlc3Qgb3Bpb2lkIHByZXNjcmlwdGlvbiBjbGFpbXMgDQppbiBQYXJ0IEQgaW4gMjAxNi4gQW5kIHRoZSB0b3AgZml2ZSBTdGF0ZXMgd2l0aCB0aGUgbG93ZXN0IA0Kb3Bpb2lkIHByZXNjcmlwdGlvbiBjbGFpbXMgaW4gUGFydCBEIGluIDIwMTYgYXJlIERpc3RyaWN0IG9mIENvbHVtYmlhLCANCkFsYXNrYSwgV3lvbWluZywgVmVybW9udCwgYW5kIEhhd2FpaS4gICAgICAgDQogICAgICAgICANCiMjIyAoMikgQ2FuIHlvdSB2aXN1YWxpemUgdGhlIHRvcCBmaXZlIFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IGFuZCBsb3dlc3Qgb3Bpb2lkIHByZXNjcmlwdGlvbiBpbiBQYXJ0IEQgaW4gMjAxNiBhbW9uZyB0aGUgZmlmdHkgU3RhdGVzIGFuZCBEQyAod2l0aCBvbmx5IHRoZXNlIFN0YXRlcyBzaG93bik/ICAgICAgDQoNCmBgYHtyIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NX0NCnAgPC0gcHJlc2NyaWJlcjIwMTZieVN0YXRlICU+JSANCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHJlZ2lvbiAhPSAiT3RoZXJzIikgJT4lDQogICAgICAgICAgICAgICAgICAgIGFycmFuZ2UoLiwtdG90YWxfb3Bpb2lkX2NsYWltKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHJvd19udW1iZXIoKSAlaW4lIGMoMTo1LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuKCktNCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4oKS0zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuKCktMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbigpLTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4oKSAjIG4oKSBtZWFucyB0aGUgbnVtYmVyIG9mIHJvd3MNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIFRodXMsIG4oKSBpcyB0aGUgb25lIHdpdGggaGlnaGV0IHRvdGFsX29waW9pZF9jbGFpbQ0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgbXV0YXRlKHJhbmtncm91cCA9IGlmZWxzZShyb3dfbnVtYmVyKCk8PTUsIkxvd2VzdCBmaXZlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiSGlnaGVzdCBmaXZlIikpICU+JQ0KICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihzdGF0ZV9uYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtdG90YWxfb3Bpb2lkX2NsYWltKSwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeT10b3RhbF9vcGlvaWRfY2xhaW0pKSArIA0KICAgICAgICAgICAgICAgICAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpDQoNCg0KcCArIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKw0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgZmFjZXRfd3JhcCh+cmFua2dyb3VwLCBzY2FsZXM9ImZyZWUiKSArDQogICAgdGhlbWVfYncoKSArIA0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwgDQogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSksDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEsdmp1c3QgPSAwLjUpKSArIA0KICAgIGdndGl0bGUoIlRvdGFsIG9waW9pZCBjbGFpbXMgKGluIE1lZGljYXJlIFBhcnQgRCkgYnkgU3RhdGUgaW4gMjAxNiIsDQogICAgICAgICAgICBzdWJ0aXRsZSA9ICJUb3AgZml2ZSBTdGF0ZXMgd2l0aCB0aGUgaGlnaGVzdCBhbmQgbG93ZXN0IG9waW9pZCBwcmVzY3JpcHRpb24iKSArIA0KICAgIHhsYWIoIlN0YXRlcyIpICsgDQogICAgeWxhYigiTnVtYmVyIG9mIG9waW9pZCBjbGFpbXMiKSANCmBgYA0KICAgICAgIA0KICAgIA0KIyMjICgzKSBBcmUgeW91IHNhdGlzZmllZCB3aXRoIHRoZSBwbG90cz8gICAgICAgICAgICAgICAgDQpUaGUgcGxvdHMgZGlkIHNob3cgdGhlIG51bWJlcnMgb2YgdG90YWwgb3Bpb2lkIGNsYWltcyByaWdodC4gDQpIb3dldmVyLCB0aGUgYXVkaWVuY2UgbmVlZCB0byByZWFkIHRoZSB4LWF4aXMgY2FyZWZ1bGx5LiANCk90aGVyd2lzZSwgdGhleSBtYXkgbWlzaW50ZXJwcmV0IHRoZSByZXN1bHRzIHNpbmNlIHRoZSBzY2FsZXMgDQphcmUgc28gZGlmZmVyZW50LiBJbiB0aGlzIGNhc2UsIGl0IG1heSBiZSBhIGdvb2QgaWRlYSB0byBzaG93IA0KYSB0YWJsZSB3aXRoIHRoZSBudW1iZXJzLiAgICAgDQoNCmBgYHtyIGZpZy53aWR0aD04LGZpZy5oZWlnaHQ9NX0NCnByZXNjcmliZXIyMDE2YnlTdGF0ZSAlPiUgDQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihyZWdpb24gIT0gIk90aGVycyIpICU+JQ0KICAgICAgICAgICAgICAgICAgICBhcnJhbmdlKC4sLXRvdGFsX29waW9pZF9jbGFpbSkgJT4lDQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihyb3dfbnVtYmVyKCkgJWluJSBjKDE6NSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbigpLTQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4oKS0zLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuKCktMiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbigpLTEsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4oKSkpICU+JQ0KICAgICAgICAgICAgICAgICAgICBzZWxlY3Qoc3RhdGVfbmFtZSx0b3RhbF9vcGlvaWRfY2xhaW0pICU+JQ0KICAgICAgICAgICAgICAgICAgICBrYWJsZSgpICU+JQ0KICAgICAgICAgICAgICAgICAgICBrYWJsZV9zdHlsaW5nKCkNCg0KYGBgDQogICAgIA0KQWx0ZXJuYXRpdmVseSwgeW91IGNhbiBzaG93IHRoZSB0b3AgNSBieSAgDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTV9DQpwcmVzY3JpYmVyMjAxNmJ5U3RhdGUgJT4lIA0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocmVnaW9uICE9ICJPdGhlcnMiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgYXJyYW5nZSguLC10b3RhbF9vcGlvaWRfY2xhaW0pICU+JQ0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocm93X251bWJlcigpICVpbiUgYygxOjUpKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHN0YXRlX25hbWUsdG90YWxfb3Bpb2lkX2NsYWltKSAlPiUNCiAgICAgICAgICAgICAgICAgICAga2FibGUoKSAlPiUNCiAgICAgICAgICAgICAgICAgICAga2FibGVfc3R5bGluZygpDQpgYGAgICAgDQogICAgDQpBbmQgeW91IGNhbiBzaG93IHRoZSBsb3dlciA1IGJ5IA0KYGBge3IgZmlnLndpZHRoPTgsZmlnLmhlaWdodD01fQ0KDQpwcmVzY3JpYmVyMjAxNmJ5U3RhdGUgJT4lIA0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocmVnaW9uICE9ICJPdGhlcnMiKSAlPiUNCiAgICAgICAgICAgICAgICAgICAgYXJyYW5nZSguLC10b3RhbF9vcGlvaWRfY2xhaW0pICU+JQ0KICAgICAgICAgICAgICAgICAgICBmaWx0ZXIocm93X251bWJlcigpICVpbiUgYyhuKCktNCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbigpLTMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG4oKS0yLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuKCktMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbigpKSkgJT4lDQogICAgICAgICAgICAgICAgICAgIHNlbGVjdChzdGF0ZV9uYW1lLHRvdGFsX29waW9pZF9jbGFpbSkgJT4lDQogICAgICAgICAgICAgICAgICAgIGthYmxlKCkgJT4lDQogICAgICAgICAgICAgICAgICAgIGthYmxlX3N0eWxpbmcoKQ0KDQpgYGAgICAgDQoNCiAgICAgDQojIyMgKDQpIEhvdyBkbyB5b3UgZmVlbCBhYm91dCB0aGUgcmVzdWx0cz8gRG8gdGhlIHJlc3VsdHMgc3VycHJpc2UgeW91PyAgICAgICAgICAgICAgIA0KDQpQcm9iYWJseSB5b3UncmUgbm90IHN1cnByaXNlZCBieSB0aGUgcmVzdWx0cywgc2luY2UgDQp0aGUgcG9wdWxhdGlvbiBpbiBDYWxpZm9ybmlhLCBGbG9yaWRhLCBhbmQgVGV4YXMgaXMgbGFyZ2UsIGFuZCANCnRoZSBwb3B1bGF0aW9uIGluIERpc3RyaWN0IG9mIENvbHVtYmlhLCBBbGFza2EsIGFuZCBXeW9taW5nIGlzIHNtYWxsLiAgIA0KVG8gbWFrZSBhIGZhaXIgY29tcGFyaXNvbiBhY3Jvc3MgDQpkaWZmZXJlbnQgU3RhdGVzLCB3ZSBtYXkgd2FudCB0byBhZGp1c3QgZm9yICJzaXplIG9mIFN0YXRlcy4iIFRoZXJlIGFyZSBtYW55IA0KZ29vZCBvcHRpb25zIHRvIGFjaGlldmUgdGhpcyBnb2FsLiBJbiB0aGlzIGNhc2Ugc3R1ZHksIHdlIHByb3ZpZGUgdHdvIHBvdGVudGlhbCANCm1ldGhvZHM6ICAgICAgDQoNCiAgKDEpIENyZWF0ZSBhIHZhcmlhYmxlIGNhbGxlZCAqKm9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSoqIChkZWZpbmVkIGJ5IENNUykuICoqT3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlKiogaXMgdGhlIHByb3BvcnRpb24gb2Ygb3Bpb2lkIGNsYWltcyBhbW9uZyB0aGUgdG90YWwgY2xhaW1zIGluIA0KYSBjZXJ0YWluIHllYXIuIFNpbmNlIHRvdGFsIGNsYWltcyBjYW4gYmUgYSBwcm94eSBvZiB0aGUgbnVtYmVyIG9mIGVucm9sbG1lbnRzIGluIA0KUGFydCBELCAqKm9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSoqIGNhbiBiZSBjb25zaWRlcmVkIGFzIGEgZmFpciBjb21wYXJpc29uIGFjcm9zcyBTdGF0ZXMuICAgIA0KDQogICgyKSBDcmVhdGUgYSB2YXJpYWJsZSBjYWxsZWQgKipvcGlvaWQgcHJlc2NyaXB0aW9uIGNsYWltcyBwZXIgMTAwIGVucm9sbG1lbnRzKiogLiANClNpbmNlIHRoZSBlbnJvbGxtZW50IG51bWJlciBieSBTdGF0ZXMgd2FzIGF2YWlsYWJsZSBpbiAyMDE1LCB3ZSBjYW4gY3JlYXRlIHRoaXMgDQp2YXJpYWJsZSB0byBkaXJlY3RseSBhZGp1c3QgZm9yIHRoZSBwb3B1bGF0aW9uIHNpemUuIChQbGVhc2UgbGV0IHVzIGtub3cgaWYgDQp0aGVyZSdzIGFueSBwdWJsaWNseSBhdmFpbGFibGUgaW5mb3JtYXRpb24gYWJvdXQgUGFydCBEIGVucm9sbG1lbnQgYnkgU3RhdGVzIGluIHRoZSBvdGhlciB5ZWFycy4pICAgICAgDQogICAgICAgDQpUbyB2aXN1YWxpemUgb3VyIGh5cG90aGVzaXMsIHdlIHdpbGwgaGF2ZSB0d28gcGxvdHM6ICAgIA0KICAoMSkgVGhlIHBsb3Qgc2hvd2luZyB0aGUgbnVtYmVyIG9mIGVucm9sbG1lbnRzIHZlcnN1cyBudW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyAgICAgDQpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD04fQ0KbGlicmFyeShnZ3JlcGVsKQ0KcCA8LSBwcmVzY3JpYmVyMjAxNWJ5U3RhdGUgJT4lIA0KICAgICAgZmlsdGVyKHJlZ2lvbiAhPSAiT3RoZXJzIikgJT4lDQogICAgICBnZ3Bsb3QoYWVzKHggPSBlbnJvbGxtZW50X251bTIwMTUsDQogICAgICAgICAgICAgICAgIHkgPSB0b3RhbF9vcGlvaWRfY2xhaW0sDQogICAgICAgICAgICAgICAgIGNvbG9yID0gcmVnaW9uKSkgKyANCiAgICAgIGdlb21fcG9pbnQoKSArIA0KICAgICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gImxtIiwgY29sID0gImJsdWUiKQ0KDQpwICsgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArIA0KICAgIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKw0KICAgIHRoZW1lX2J3KCkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksDQogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSApLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLHZqdXN0ID0gMC41KSkgKyANCiAgICBnZ3RpdGxlKCJOdW1iZXIgb2YgZW5yb2xsbWVudHMgdnMuIE9waW9pZCBwcmVzY3JpcHRpb24gY2xhaW1zIGluIE1lZGljYXJlIFBhcnQgRFwgYnkgU3RhdGUgaW4gMjAxNSIsDQogICAgICAgICAgICBzdWJ0aXRsZSA9ICJOdW1iZXIgb2YgZW5yb2xsbWVudHMgaXMgYXNzb2NpYXRlZCB3aXRoIG51bWJlciBvZiBvcGlvaWQgcHJlc2NyaXB0aW9ucyIpICsgDQogICAgeGxhYigiIE51bWJlciBvZiBlbnJvbGxtZW50cyAiKSArIA0KICAgIHlsYWIoIiBOdW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyAiKSArIA0KICAgIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWw9YG5wcGVzIHByb3ZpZGVyIHN0YXRlYCkpIA0KDQpgYGANCiAgICAgICAgICANCigyKSBUaGUgcGxvdCBzaG93aW5nIHRoZSBudW1iZXIgb2YgdG90YWwgY2xhaW1zIHZlcnN1cyBudW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyAgICAgDQpgYGB7ciBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD04fQ0KcCA8LSBwcmVzY3JpYmVyMjAxNWJ5U3RhdGUgJT4lIA0KICAgICAgZmlsdGVyKHJlZ2lvbiAhPSAiT3RoZXJzIikgJT4lDQogICAgICBnZ3Bsb3QoYWVzKHggPSB0b3RhbF9jbGFpbV9jb3VudCwNCiAgICAgICAgICAgICAgICAgeSA9IHRvdGFsX29waW9pZF9jbGFpbSwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSByZWdpb24pKSArIA0KICAgICAgZ2VvbV9wb2ludCgpICsgDQogICAgICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iLCBjb2wgPSAiYmx1ZSIpDQoNCnAgKyBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEpICsgDQogICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArDQogICAgdGhlbWVfYncoKSArIA0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwNCiAgICAgICAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEsdmp1c3QgPSAwLjUpKSArIA0KICAgIGdndGl0bGUoIlRvdGFsIGNsYWltcyB2cy4gT3Bpb2lkIHByZXNjcmlwdGlvbiBjbGFpbXMgaW4gTWVkaWNhcmUgUGFydCBEXCBieSBTdGF0ZSBpbiAyMDE1IiwNCiAgICAgICAgICAgIHN1YnRpdGxlID0gIk51bWJlciBvZiB0b3RhbCBjbGFpbXMgaXMgYXNzb2NpYXRlZCB3aXRoIG51bWJlciBvZiBvcGlvaWQgcHJlc2NyaXB0aW9ucyIpICsgDQogICAgeGxhYigiIE51bWJlciBvZiB0b3RhbCBjbGFpbXMgIikgKyANCiAgICB5bGFiKCIgTnVtYmVyIG9mIG9waW9pZCBjbGFpbXMgIikgKyANCiAgICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPWBucHBlcyBwcm92aWRlciBzdGF0ZWApKSANCg0KYGBgICAgICAgICAgIA0KDQojIyAyLiBDb21wYXJpbmcgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlIGJ5IFN0YXRlIGluIDIwMTYgDQpgYGB7ciBmaWcud2lkdGg9OCxmaWcuaGVpZ2h0PTh9DQpwIDwtIHByZXNjcmliZXIyMDE2YnlTdGF0ZSAlPiUgDQogICAgICAgICAgICAgICAgICAgIGZpbHRlcihyZWdpb24gIT0gIk90aGVycyIpICU+JQ0KICAgICAgICAgICAgICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihzdGF0ZV9uYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUpLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5PXN0YXRlX29waW9pZF9wcmVzY3JpYmluZ19yYXRlKSkgKyANCiAgICAgICAgICAgICAgICAgICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKQ0KDQpwICsgdGhlbWVfYncoKSArIA0KICAgIGNvb3JkX2ZsaXAoKSArDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSApLCANCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSx2anVzdCA9IDAuNSkpICsgDQogICAgZ2d0aXRsZSgiT3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIGluIDIwMTYiKSArIA0KICAgIHhsYWIoIlN0YXRlcyIpICsgDQogICAgeWxhYigiT3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChOdW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyBwZXIgMTAwIGNsYWltcykiKSAgIA0KYGBgDQogICAgICANCkZyb20gdGhpcyBwbG90LCB3ZSBjYW4gc2VlIHRoYXQgaW4gUGFydCBEIGluIDIwMTYsIA0KdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZXMgaW4gTmV2YWRhLCBVdGFoLCBBbGFiYW1hLCBPa2xhaG9tYSwgSWRhaG8gYXJlIHRoZSBoaWdoZXN0LCANCmFuZCB0aGUgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlcyBpbiBOZXcgWW9yaywgUmhvZGUgSXNsYW5kLCBIYXdhaWksIA0KTWFzc2FjaHVzZXR0cywgYW5kIE5vcnRoIERha290YSBhcmUgdGhlIGxvd2VzdC4gICAgICAgICANCiAgICAgDQojIyAzLiBUcmVuZCBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgaW4gMjAxMyAtIDIwMTYgIA0KV2UgbWF5IHdhbnQgdG8gc2VlIHRoZSB0cmVuZCBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgZHVyaW5nIDIwMTMgYW5kIDIwMTYgYnkgU3RhdGUuICAgDQogICAgICANCiMjIyBWaXN1YWxpemUgdGhlIGNoYW5nZSBieSBTdGF0ZXMgdXNpbmcgYmFyIGNoYXJ0ICAgICANCiAgICAgDQpIZXJlLCB3ZSBhcHBlbmQgdGhlIGRhdGEgZnJvbSBkaWZmZXJlbnQgeWVhcnMgaW4gKipsb25nIGZvcm1hdCoqIGZpcnN0LCANCmFuZCB0aGVuIHBsb3QgdGhlIHRyZW5kIG9mIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZS4gICAgIA0KYGBge3IgZmlnLndpZHRoPTgsZmlnLmhlaWdodD04fQ0KcCA8LSBwcmVzY3JpYmVyMjAxNmJ5U3RhdGUgJT4lIA0KICAgICAgICB1bmlvbiguLHByZXNjcmliZXIyMDE1YnlTdGF0ZSkgJT4lDQogICAgICAgIHVuaW9uKC4scHJlc2NyaWJlcjIwMTRieVN0YXRlKSAlPiUNCiAgICAgICAgdW5pb24oLixwcmVzY3JpYmVyMjAxM2J5U3RhdGUpICU+JQ0KICAgICAgICBmaWx0ZXIocmVnaW9uICE9ICJPdGhlcnMiKSAlPiUNCiAgICAgICAgZ2dwbG90KGFlcyh4PXJlb3JkZXIoc3RhdGVfbmFtZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLXN0YXRlX29waW9pZF9wcmVzY3JpYmluZ19yYXRlKSwgDQogICAgICAgICAgICAgICAgICAgeT1zdGF0ZV9vcGlvaWRfcHJlc2NyaWJpbmdfcmF0ZSwNCiAgICAgICAgICAgICAgICAgICBmaWxsID0gYXMuZmFjdG9yKHllYXIpKSkgKyANCiAgICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpDQoNCnAgKyB0aGVtZV9idygpICsNCiAgICBjb29yZF9mbGlwKCkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksIA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLHZqdXN0ID0gMC41KSkgKyANCiAgICBnZ3RpdGxlKCJUcmVuZCBvZiBvcGlvaWQgUHJlc2NyaXB0aW9uIFJhdGUgKGluIE1lZGljYXJlIFBhcnQgRCkgYnkgU3RhdGUgZHVyaW5nIDIwMTMgLSAyMDE2IikgKyANCiAgICB4bGFiKCJTdGF0ZXMiKSArIA0KICAgIHlsYWIoIk9waW9pZCBQcmVzY3JpcHRpb24gUmF0ZSAoTnVtYmVyIG9mIG9waW9pZCBjbGFpbXMgcGVyIDEwMCBjbGFpbXMpIikgICArIA0KICAgIGxhYnMoZmlsbCA9ICJZZWFyIikNCmBgYCAgDQojIyMgVmlzdWFsaXplL0FuaW1hdGUgdGhlIGNoYW5nZSBieSBTdGF0ZXMgdXNpbmcgYmFyIGNoYXJ0ICAgICANCiAgICAgDQpUaGUgYWx0ZXJuYXRpdmUgYXBwcm9hY2ggaXMgdG8gYW5pbWF0ZSB0aGVyIHJlc3VsdHMgdXNpbmcgYGdnYW5pbWF0ZWAuICAgICAgICANCmBgYHtyIGV2YWw9VFJVRX0NCiMgPFJlZiAxPiBodHRwczovL2dnYW5pbWF0ZS5jb20vYXJ0aWNsZXMvZ2dhbmltYXRlLmh0bWwNCiMgPFJlZiAyPiBodHRwczovL3Rvd2FyZHNkYXRhc2NpZW5jZS5jb20vY3JlYXRlLWFuaW1hdGVkLWJhci1jaGFydHMtdXNpbmctci0zMWQwOWU1ODQxZGENCmxpYnJhcnkoZ2dhbmltYXRlKQ0KbGlicmFyeShnaWZza2kpDQoNCmRhdGE0YW5pbWF0aW9uIDwtICBwcmVzY3JpYmVyMjAxNmJ5U3RhdGUgJT4lIA0KICAgICAgICB1bmlvbiguLHByZXNjcmliZXIyMDE1YnlTdGF0ZSkgJT4lDQogICAgICAgIHVuaW9uKC4scHJlc2NyaWJlcjIwMTRieVN0YXRlKSAlPiUNCiAgICAgICAgdW5pb24oLixwcmVzY3JpYmVyMjAxM2J5U3RhdGUpICU+JQ0KICAgICAgICBmaWx0ZXIocmVnaW9uICE9ICJPdGhlcnMiKSAlPiUNCiAgICAgICAgZ3JvdXBfYnkoeWVhcikgJT4lDQogICAgICAgIG11dGF0ZShyYW5rID0gcmFuaygtc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUpLA0KICAgICAgICAgICAgICAgdmFsdWVfcmVsID0gc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUvc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGVbcmFuaz09MV0sDQogICAgICAgICAgICAgICB2YWx1ZV9zdGQgPSByb3VuZChzdGF0ZV9vcGlvaWRfcHJlc2NyaWJpbmdfcmF0ZSwyKSkgJT4lDQogICAgICAgIGdyb3VwX2J5KHN0YXRlX25hbWUpICU+JSANCiAgICAgICAgZmlsdGVyKHJhbmsgPD0gMjApICU+JSAjIGNob29zZSB0aGUgdG9wIDIwDQogICAgICAgIHVuZ3JvdXAoKQ0KDQpzdGF0aWNwbG90ID0gZ2dwbG90KGRhdGE0YW5pbWF0aW9uLCANCiAgICAgICAgICAgICAgICAgICAgYWVzKHJhbmssIA0KICAgICAgICAgICAgICAgICAgICAgICAgZ3JvdXAgPSBzdGF0ZV9uYW1lLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSBhcy5mYWN0b3Ioc3RhdGVfbmFtZSksIA0KICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBhcy5mYWN0b3Ioc3RhdGVfbmFtZSkpKSArDQogIGdlb21fdGlsZShhZXMoeSA9IHJvdW5kKHN0YXRlX29waW9pZF9wcmVzY3JpYmluZ19yYXRlLzIsMiksDQogICAgICAgICAgICAgICAgaGVpZ2h0ID0gcm91bmQoc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUsMiksDQogICAgICAgICAgICAgICAgd2lkdGggPSAwLjkpLCBhbHBoYSA9IDAuOCwgY29sb3IgPSBOQSkgKw0KICBnZW9tX3RleHQoYWVzKHkgPSAwLCBsYWJlbCA9IHBhc3RlKHN0YXRlX25hbWUsICIgIikpLCB2anVzdCA9IDAuMiwgaGp1c3QgPSAxKSArDQogIGdlb21fdGV4dChhZXMoeT0gdmFsdWVfc3RkLA0KICAgICAgICAgICAgICAgIGxhYmVsID0gdmFsdWVfc3RkLCBoanVzdD0wKSkgKw0KICBjb29yZF9mbGlwKGNsaXAgPSAib2ZmIiwgZXhwYW5kID0gRkFMU0UpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6Y29tbWEpICsNCiAgc2NhbGVfeF9yZXZlcnNlKCkgKw0KICBndWlkZXMoY29sb3IgPSBGQUxTRSwgZmlsbCA9IEZBTFNFKSArDQogIHRoZW1lKGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aXRsZS54PWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIsDQogICAgICAgIHBhbmVsLmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBwYW5lbC5ncmlkLm1ham9yPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vcj1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfbGluZSggc2l6ZT0uMSwgY29sb3I9ImdyZXkiICksDQogICAgICAgIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfbGluZSggc2l6ZT0uMSwgY29sb3I9ImdyZXkiICksDQogICAgICAgIHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsIGhqdXN0PTAuNSwgZmFjZT0iYm9sZCIsIGNvbG91cj0iZ3JleSIsIHZqdXN0PS0xKSwNCiAgICAgICAgcGxvdC5zdWJ0aXRsZT1lbGVtZW50X3RleHQoc2l6ZT02LCBoanVzdD0wLjUsIGZhY2U9Iml0YWxpYyIsIGNvbG9yPSJncmV5IiksDQogICAgICAgIHBsb3QuY2FwdGlvbiA9ZWxlbWVudF90ZXh0KHNpemU9NiwgaGp1c3Q9MC41LCBmYWNlPSJpdGFsaWMiLCBjb2xvcj0iZ3JleSIpLA0KICAgICAgICBwbG90LmJhY2tncm91bmQ9ZWxlbWVudF9ibGFuaygpICAsDQogICAgICAgcGxvdC5tYXJnaW4gPSBtYXJnaW4oMiwyLCAxLCAzLCAiY20iKSkNCg0Kc3RhdGljcGxvdA0KDQphbmltYXRpb246OmFuaS5vcHRpb25zKGFuaS53aWR0aD0gMTAwMCwgYW5pLmhlaWdodD0xMDAwLCBhbmkucmVzID0gMTAwMCkNCmFuaW0gPSBzdGF0aWNwbG90ICsgdHJhbnNpdGlvbl9zdGF0ZXMoeWVhciwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyYW5zaXRpb25fbGVuZ3RoID0gMywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXRlX2xlbmd0aCA9IDIpICsNCiAgdmlld19mb2xsb3coZml4ZWRfeCA9IFRSVUUpICArDQogIGxhYnModGl0bGUgPSAiVHJlbmQgb2Ygb3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIHtjbG9zZXN0X3N0YXRlfSIsICANCiAgICAgICBzdWJ0aXRsZSAgPSAgIk9waW9pZCBQcmVzY3JpcHRpb24gUmF0ZSAoTnVtYmVyIG9mIG9waW9pZCBjbGFpbXMgcGVyIDEwMCBjbGFpbXMpIiwNCiAgICAgICBjYXB0aW9uICA9ICJEYXRhIFNvdXJjZTogQ01TIERhdGEiDQogICAgICAgKQ0KYW5pbSANCg0KIyBUaGlzIGlzIHRoZSBsaW5lIHRvIHNhdmUgdGhlIGFuaW1hdGlvbiBpbnRvIGdpZiBmb3JtYXQNCiMgYW5pbWF0ZShhbmltLCAyMDAsIGZwcyA9IDIwLCAgd2lkdGggPSAxMjAwLCBoZWlnaHQgPSAxMDAwLCANCiMgICAgICAgICByZW5kZXJlciA9IGdpZnNraV9yZW5kZXJlcigiLi9pbWcvZ2dhbmltLmdpZiIpKQ0KYGBgDQogICAgICANCkluIGdlbmVyYWwsIHRoZSB0cmVuZCB0aGUgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlIHdhcyBkZWNyZWFzaW5nIGR1cmluZyAyMDEzIC0gMjAxNiBhY3Jvc3MgbW9zdCBvZiB0aGUgU3RhdGVzLiAgICANCg0KIyMjIExldCB1cyB2aXN1YWxpemUgdGhlIHZhcmlhdGlvbiBkdXJpbmcgdGhlIHBlcmlvZCBvZiAyMDEzIC0gMjAxNiBhY3Jvc3MgZGlmZmVyZW50IFN0YXRlcyAgICAgDQoqIEhlcmUsIHdlIGRlZmluZSB0aGUgInZhcmlhdGlvbiBkdXJpbmcgdGhlIHBlcmlvZCBvZiAyMDEzIC0gMjAxNiIgYXMgDQp0aGUgcmF0aW8gYmV0d2VlbiAidGhlIGRpZmZlcmVuY2UgYmV0d2VlbiBtYXhpbXVtIG9waW9pZCBwcmVzY3JpcHRpb24gYW5kIA0KbWluaW11bSBvcGlvaWQgcHJlc2NyaXB0aW9uIGR1cmluZyAyMDEzIC0gMjAxNiIgYW5kICJ0aGUgbWF4aW11bSBvcGlvaWQgDQpwcmVzY3JpcHRpb24gZHVyaW5nIDIwMTMgLSAyMDE2IiAuICANCmBgYHtyIGZpZy53aWR0aD0xMixmaWcuaGVpZ2h0PTh9DQpmb3VyeWVhcmRhdGEgPC0gcHJlc2NyaWJlcjIwMTZieVN0YXRlICU+JSANCiAgICAgICAgdW5pb24oLixwcmVzY3JpYmVyMjAxNWJ5U3RhdGUpICU+JQ0KICAgICAgICB1bmlvbiguLHByZXNjcmliZXIyMDE0YnlTdGF0ZSkgJT4lDQogICAgICAgIHVuaW9uKC4scHJlc2NyaWJlcjIwMTNieVN0YXRlKSAlPiUNCiAgICAgICAgZmlsdGVyKHJlZ2lvbiAhPSAiT3RoZXJzIikgJT4lDQogICAgICAgIGdyb3VwX2J5KHN0YXRlX25hbWUpICU+JQ0KICAgICAgICBzdW1tYXJpc2UobWF4X29waW9pZF9jbGFpbSA9IG1heCh0b3RhbF9vcGlvaWRfY2xhaW0pLA0KICAgICAgICAgICAgICAgICAgbWluX29waW9pZF9jbGFpbSA9IG1pbih0b3RhbF9vcGlvaWRfY2xhaW0pKSAlPiUNCiAgICAgICAgbXV0YXRlKHZhcmlhdGlvbiA9IChtYXhfb3Bpb2lkX2NsYWltIC0gbWluX29waW9pZF9jbGFpbSkgLyBtYXhfb3Bpb2lkX2NsYWltICkNCg0KcCA8LSBmb3VyeWVhcmRhdGEgJT4lDQogICAgICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihzdGF0ZV9uYW1lLC12YXJpYXRpb24pLCANCiAgICAgICAgICAgICAgICAgeT12YXJpYXRpb24pKSArIA0KICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpDQoNCnAgKyB0aGVtZV9idygpICsgDQogICAgY29vcmRfZmxpcCgpICsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksDQogICAgICAgICAgcGxvdC5zdWJ0aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSApLA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLHZqdXN0ID0gMC41KSkgKyANCiAgICBnZ3RpdGxlKCJWYXJpYXRpb24gb2YgdG90YWwgb3Bpb2lkIGNsYWltcyAoaW4gTWVkaWNhcmUgUGFydCBEKSBieSBTdGF0ZSBkdXJpbmcgMjAxMyAtIDIwMTYiLA0KICAgICAgICAgICAgc3VidGl0bGUgPSAiVmFyaWF0aW9uID0gKG1heGltdW4gb3Bpb2lkIGNsYWltcyAtIG1pbmltdW0gb3Bpb2lkIGNsYWltcykgLyBtYXhpbXVtIG9waW9pZCBjbGFpbXMiKSArIA0KICAgIHhsYWIoIlN0YXRlcyIpICsgDQogICAgeWxhYigiVmFyaWF0aW9uIG9mIHRvdGFsIG9waW9pZCBjbGFpbXMiKSANCg0KYGBgDQoNCiMjIyBBbHRlcm5hdGl2ZSB3YXkgdG8gZGlzcGxheSB0aGUgbG9uZ2l0dWRpbmFsIHRyZW5kcyAgICAgIA0KVGhlcmUgYXJlIG1hbnkgd2F5cyB0byBkaXNwbGF5IHRoZSBsb25naXR1ZGluYWwgdHJlbmRzIG9mIG9waW9pZCBwcmVzY3JpcHRpb24gDQpyYXRlLiBJbiB0aGUgcGxvdCBzaG93biBhYm92ZSwgdGhlIGxvbmdpdHVkaW5hbCBjaGFuZ2Ugd2FzIHNob3duIGNsZWFybHkgYnkgU3RhdGVzLiANCkhvd2V2ZXIsIGl0IGhhcyBzb21lIGRpc2FkdmFudGFnZXM6ICAgDQooMSkgSXQgaXMgZGlmZmljdWx0IGZvciB1cyB0byBjb21wYXJlIHRoZSB0cmVuZCBmcm9tIFN0YXRlIHRvIFN0YXRlIGRpcmVjdGx5LiAgICAgICANCigyKSBJdCBpcyBoYXJkIGZvciB1cyB0byBleHBsb3JlIHRoZSBwb3RlbnRpYWwgcmVhc29ucyB0byBleHBsYWluIHRoZSBkaWZmZXJlbmNlIA0KYmV0d2VlbiBkaWZmZXJlbnQgU3RhdGVzLiAgIA0KTm93LCBzdXBwb3NlIHdlIHdhbnQgdG8gdmlzdWFsbHkgZXhwbG9yZSB3aGV0aGVyIHRoZSBjaGFuZ2UgaW4gb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlIA0Kb3ZlciB0aW1lIHdhcyBhc3NvY2lhdGUgd2l0aCByZWdpb24sIHdlIG1heSB3YW50IHRvIGhhdmUgYSBwbG90IHNob3dpbmcgDQp0aGUgY2hhbmdlcyBvdmVyIHRpbWUgYnkgU3RhdGVzLCB3aGljaCBhbHNvIGluY29ycG9yYXRlZCB0aGUgcmVnaW9uIGluZm9ybWF0aW9uLiANCkJhc2VkIG9uIHdoYXQgd2UgaGF2ZSBlc3RhYmxpc2hlZCwgd2UgbmVlZCB0byBvcmdhbml6ZSBvdXIgZGF0YSBpbiBgbG9uZyBmb3JtYXRgIA0KYW5kIGFkZCB0aGUgYGdyb3VwYCBpbmZvcm1hdGlvbiBpbiBvdXIgYGdncGxvdGAuICAgDQpgYGB7ciB3YXJuaW5nPVRSVUUsIG1lc3NhZ2U9VFJVRSwgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9OH0NCmRhdGFtb2RlbCA8LSBwcmVzY3JpYmVyMjAxNmJ5U3RhdGUgJT4lIA0KICAgICAgICB1bmlvbiguLHByZXNjcmliZXIyMDE1YnlTdGF0ZSkgJT4lDQogICAgICAgIHVuaW9uKC4scHJlc2NyaWJlcjIwMTRieVN0YXRlKSAlPiUNCiAgICAgICAgdW5pb24oLixwcmVzY3JpYmVyMjAxM2J5U3RhdGUpICU+JQ0KICAgICAgICBmaWx0ZXIocmVnaW9uICE9ICJPdGhlcnMiKSAlPiUNCiAgICAgICAgbXV0YXRlKGludGVydmFsID0geWVhciAtIDIwMTMpDQoNCnAgPC0gZGF0YW1vZGVsICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCANCiAgICAgICAgICAgICB5ID0gc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUsIA0KICAgICAgICAgICAgIGdyb3VwID0gc3RhdGVfbmFtZSwNCiAgICAgICAgICAgICBjb2xvciA9IHJlZ2lvbikpICsgDQogIGdlb21fbGluZSgpDQoNCg0KcCArIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwgDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDAuNSx2anVzdCA9IDAuNSkpICsgDQogICAgZ2d0aXRsZSgiVHJlbmQgb2Ygb3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIGR1cmluZyAyMDEzIC0gMjAxNiIpICsgDQogICAgeGxhYigiQ2FsZW5kZXIgWWVhciIpICsgDQogICAgeWxhYigiT3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChOdW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyBwZXIgMTAwIGNsYWltcykiKSAgKyANCiAgICBsYWJzKGNvbG9yID0gIlJlZ2lvbiIpIA0KYGBgICAgICAgDQogICAgICANCkFsc28sIHlvdSBtYXkgd2FudCB0byBhZGQgYSAic3VtbWFyaXplZCIgbGluZSBmb3IgZWFjaCByZWdpb24uIA0KSW4gb3RoZXIgd29yZHMsIHRoZSBxdWVzdGlvbiBpcyB3aGV0aGVyIHdlIGNhbiB2aXN1YWxseSBkaXNwbGF5IA0KdGhlIHN1bW1hcml6ZWQgbG9uZ2l0dWRpbmFsIHRyZW5kIGluIGVhY2ggcmVnaW9uLiBIZXJlLCB3ZSBwcm92aWRlIA0KYSB3YXkgdGhhdCBjYW4gYWNoaWV2ZSB0aGlzIGdvYWwgaW4gYSBmZXcgc2Vjb25kcy4gVGhlIGlkZWEgaXMgDQp0byB0YWtlIHRoZSBhdmVyYWdlIG9mIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSBpbiBlYWNoIHJlZ2lvbiBhdCANCnllYXIgMjAxMywgMjAxNCwgMjAxNSwgYW5kIDIwMTYsIGFuZCBmdXJ0aGVyIHRoZW4gcGxvdCB0aGUgdHJlbmQgDQpvZiB0aGUgcmVnaW9uLXNwZWNpZmljIGF2ZXJhZ2Ugb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlIG92ZXIgdGltZS4gICANCg0KYGBge3IgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9OH0NCnAgPC0gZGF0YW1vZGVsICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSB5ZWFyLCANCiAgICAgICAgICAgICB5ID0gc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUsIA0KICAgICAgICAgICAgIGdyb3VwID0gc3RhdGVfbmFtZSwNCiAgICAgICAgICAgICBjb2xvciA9IHJlZ2lvbikpICsgDQogIHN0YXRfc3VtbWFyeShhZXMoZ3JvdXAgPSByZWdpb24pLCANCiAgICAgICAgICAgICAgIGdlb20gPSAibGluZSIsIA0KICAgICAgICAgICAgICAgZnVuLnkgPSBtZWFuLCBzaXplID0gNSkgICsNCiAgZ2VvbV9saW5lKCkNCg0KcCArIHRoZW1lX2J3KCkgKw0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwgDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDAuNSx2anVzdCA9IDAuNSkpICsgDQogICAgZ2d0aXRsZSgiVHJlbmQgb2Ygb3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIGR1cmluZyAyMDEzIC0gMjAxNiIpICsgDQogICAgeGxhYigiQ2FsZW5kZXIgWWVhciIpICsgDQogICAgeWxhYigiT3Bpb2lkIFByZXNjcmlwdGlvbiBSYXRlIChOdW1iZXIgb2Ygb3Bpb2lkIGNsYWltcyBwZXIgMTAwIGNsYWltcykiKSAgKyANCiAgICBsYWJzKGNvbG9yID0gIlJlZ2lvbiIpIA0KYGBgICAgICAgDQogICAgIA0KDQojIyA0LiBDb21wYXJpbmcgb3Bpb2lkIHByZXNjcmlwdGlvbiBieSBTdGF0ZXMgaW4gMjAxNSAgDQpTaW5jZSB0aGVyZSBhcmUgbWFueSBwb2xpY2llcyBtYWRlIGF0IFN0YXRlIGxldmVsLCBhbmQgDQppdCdzIHJlbGF0aXZlbHkgZGlmZmljdWx0IHRvIGdldCBpbmZvcm1hdGlvbiBhYm91dCB0aGUgDQpwb2xpY3kgaW4gbWlsaXRhcmllcywgZm9yZWlnbiBjb3VudHJpZXMsIGFuZCB1bmtub3duIGFyZWFzLCANCndlIG1heSB3YW50IHRvIGZvY3VzIG9uIHRoZSBhcmVhcyB3ZSBhcmUgYWJsZSB0byBnZXQgdGhlIA0KaW5mb3JtYXRpb24gYWJvdXQgdGhlIG51bWJlciBvZiBQYXJ0IEQgUGFydCBlbnJvbGxtZW50LiANCg0KICAgICAgICAgDQojIyMgTWV0aG9kIEk6IHVzaW5nICJvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUiICAgIA0KYGBge3IgZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9OH0NCnAgPC0gcHJlc2NyaWJlcjIwMTVieVN0YXRlICU+JSANCiAgICAgICAgZmlsdGVyKHJlZ2lvbiAhPSAiT3RoZXJzIikgJT4lICMgVGhpcyBsaW5lIHJlbW92ZXMgdGhlIHJlZ2lvbi9TdGF0ZXMgd2l0aG91dCBwb3B1bGF0aW9uIGluZm9ybWF0aW9uLg0KICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihzdGF0ZV9uYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUpLCANCiAgICAgICAgICAgICAgICAgICB5PXN0YXRlX29waW9pZF9wcmVzY3JpYmluZ19yYXRlKSkgKyANCiAgICAgICAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBzdGF0PSJpZGVudGl0eSIpDQoNCnAgKyB0aGVtZV9idygpICsgDQogICAgY29vcmRfZmxpcCgpICsNCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksIA0KICAgICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwNCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSx2anVzdCA9IDAuNSkpICsgDQogICAgZ2d0aXRsZSgiT3Bpb2lkIHByZXNjcmlvbiByYXRlIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIGluIDIwMTUiLA0KICAgICAgICAgICAgc3VidGl0bGUgPSAiT3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlID0gKCAjIG9mIG9waW9pZCBjbGFpbXMgLyAjIG9mIHRvdGFsIGNsYWltcyApICogMTAwICUiKSArIA0KICAgIHhsYWIoIlN0YXRlcyIpICsgDQogICAgeWxhYigiT3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlICglKSIpIA0KYGBgDQogICAgICANCiMjIyBNZXRob2QgSUk6IHVzaW5nICJvcGlvaWQgcHJlc2NyaXB0aW9uIHBlciAxMDAgZW5yb2xsbWVudHMiICAgICAgIA0KV2UgbWF5IHdhbnQgdG8gc2VlIG9waW9pZCBwcmVzY3JpcHRpb24gcGVyIDEwMCBlbnJvbGxtZW50IGluIDIwMTUuIA0KYGBge3IgZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9OH0NCnAgPC0gcHJlc2NyaWJlcjIwMTVieVN0YXRlICU+JSANCiAgICAgICAgZmlsdGVyKHJlZ2lvbiAhPSAiT3RoZXJzIikgICU+JQ0KICAgICAgICBnZ3Bsb3QoYWVzKHg9cmVvcmRlcihzdGF0ZV9uYW1lLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAtb3Bpb2lkX2NsYWltX2J5cG9wKSwgDQogICAgICAgICAgICAgICAgICAgeT1vcGlvaWRfY2xhaW1fYnlwb3ApKSArIA0KICAgICAgICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIsIHN0YXQ9ImlkZW50aXR5IikNCg0KcCArIHRoZW1lX2J3KCkgKyANCiAgICBjb29yZF9mbGlwKCkgKw0KICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSwgDQogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDEsdmp1c3QgPSAwLjUpKSArIA0KICAgIGdndGl0bGUoIk9waW9pZCBwcmVzY3JpcHRpb24gcGVyIDEwMCBlbnJvbGxtZW50cyBpbiBNZWRpY2FyZSBQYXJ0IERcbiBieSBTdGF0ZSBpbiAyMDE1IikgKyANCiAgICB4bGFiKCJTdGF0ZXMiKSArIA0KICAgIHlsYWIoIk51bWJlciBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uIGNsYWltcyBwZXIgMTAwIGVucm9sbG1lbnRzIikgICANCmBgYA0KICAgICANCiMjIyBEbyB0d28gbWV0aG9kcyBnaXZlIHVzIHNhbWUgaW5mb3JtYXRpb24/ICAgICAgDQpUaGUgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlIHdhcyBoaWdoIGluICBBbWVyaWNhbiBTYW1vYSwgYnV0IA0KdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcGVyIDEwMCBlbnJvbGxtZW50cyBpcyBsb3cgaW4gQW1lcmljYW4gU2Ftb2EuIA0KVGhpcyBtYXkgYmUgZHVlIHRvIHRoZXJlIGFyZSByZWxhdGl2ZWx5IGZldyB0b3RhbCBjbGFpbXMgaW4gQW1lcmljYW4gU2Ftb2EsIA0KYnV0IHRoZSBwcm9wb3J0aW9uIG9mIG9waW9pZCBwcmVzY3JpcHRpb24gaXMgaGlnaC4gVGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZXMgaW4gDQpVdGFoLCBOZXZhZGEsIE9rbGFob21hLCBBbGFiYW1hLCBJZGFobywgQ29sb3JhZG8sIFRlbm5lc3NlZSwgYW5kIE9yZWdvbiANCmFyZSBhbHNvIHJlbGF0aXZlbHkgaGlnaC4gVGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcGVyIDEwMCBlbnJvbGxtZW50cyBhcmUgDQpyZWxhdGl2ZWx5IGhpZ2ggaW4gVGVubmVzc2VlLCBBbGFiYW1hLCBhbmQgT2tsYWhvbWEuICAgICAgDQogICAgICANCiMjIyBDYW4geW91IHZpc3VhbGl6ZSB0aGUgaW5mb3JtYXRpb24gZnJvbSB0aGVzZSB0d28gbWV0aG9kcz8gICAgDQpUbyB2aXN1YWxpemUgdGhlIGluZm9ybWF0aW9uIGZyb20gdGhlc2UgdHdvIG1ldGhvZHMsIHdlIA0KcHJvcG9zZSB0byBjb21wYXJlIHRoZSAicmFua2luZ3MiIGZyb20gdHdvIG1ldGhvZHMuIA0KRmlyc3QsIHdlIHdpbGwgY3JlYXRlIG9uZSB2YXJpYWJsZSBjYWxsZWQgYHJhbmtfbWV0aG9kMWAsIHdoaWNoIGlzIA0KdGhlIHJhbmsgYmFzZWQgb24gdGhlIG1ldGhvZCBJIChzdGF0ZSBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUpLCANCmFuZCB0aGUgb3RoZXIgdmFyaWFibGUgY2FsbGVkIGByYW5rX21ldGhvZDJgICwgd2hpY2ggaXMgdGhlIHJhbmsgDQpiYXNlZCBvbiB0aGUgbWV0aG9kIElJIChvcGlvaWQgY2xhaW0gYnkgbnVtYmVyIG9mIGVucm9sbG1lbnQpLiANClRoaXMgY2FuIGJlIGRvbmUgYnkgdXNpbmcgdGhlIGBkZW5zZV9yYW5rKClgLiANClRoZW4sIHdlIGNhbiBoYXZlIGFuIHgteSBwbG90IHNob3dpbmcgdGhlIHJhbmtpbmcgYmV0d2VlbiB0aGVzZSANCnR3byBtZXRob2RzLiAgICAgICAgDQpgYGB7ciBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD0xMH0NCiMjIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgY2FsbGVkICJtZXRob2RfY29tcGFyaXNvbiINCm1ldGhvZF9jb21wYXJpc29uIDwtIHByZXNjcmliZXIyMDE1YnlTdGF0ZSAlPiUgDQogICAgICAgIGZpbHRlcihjb21wbGV0ZS5jYXNlcyguKSkgJT4lDQogICAgICAgIGZpbHRlcihyZWdpb24gIT0gIk90aGVycyIpICU+JQ0KICAgICAgICBtdXRhdGUocmFua19tZXRob2QxID0gZGVuc2VfcmFuayhkZXNjKHN0YXRlX29waW9pZF9wcmVzY3JpYmluZ19yYXRlKSksDQogICAgICAgICAgICAgICByYW5rX21ldGhvZDIgPSBkZW5zZV9yYW5rKGRlc2Mob3Bpb2lkX2NsYWltX2J5cG9wKSkpICU+JQ0KICAgICAgICBhcnJhbmdlKC1vcGlvaWRfY2xhaW1fYnlwb3ApDQoNCiMjIFRha2UgYSBsb29rIGF0IHRoZSAibWV0aG9kX2NvbXBhcmlzb24iDQptZXRob2RfY29tcGFyaXNvbiAlPiUNCiAgaGVhZCguKSAlPiUNCiAga2FibGUoKSAlPiUNCiAga2FibGVfc3R5bGluZygpDQoNCiMjIFBsb3QgdGhlIGNvbXBhcmlzb24gDQpwIDwtIG1ldGhvZF9jb21wYXJpc29uICU+JSANCiAgICAgIGdncGxvdChhZXMoeD1yYW5rX21ldGhvZDEsDQogICAgICAgICAgICAgICAgIHkgPSByYW5rX21ldGhvZDIsDQogICAgICAgICAgICAgICAgIGNvbG9yID0gcmVnaW9uKSkgKyANCiAgICAgIGdlb21fcG9pbnQoKSArIA0KICAgICAgZ2VvbV9hYmxpbmUoc2xvcGU9MSwgaW50ZXJjZXB0PTApDQoNCnAgKyB0aGVtZV9idygpICsgDQogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSApLCANCiAgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIGhqdXN0ID0gMSx2anVzdCA9IDAuNSkpICsgDQogICAgZ2d0aXRsZSgiQ29tcGFyaXNvbiBvZiB0d28gbWV0aG9kcyByYW5raW5nIG9waW9pZCBwcmVzY3JpcHRpb24gaW4gTWVkaWNhcmUgUGFydCBEIFxuIGJ5IFN0YXRlIGluIDIwMTUiLA0KICAgICAgICAgICAgc3VidGl0bGUgPSAiTG93ZXIgbnVtYmVyIGluIHJhbmsgbWVhbnMgaGlnaGVyIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZS4iKSArIA0KICAgIHhsYWIoIlJhbmsgYnkgTWV0aG9kIEkgKG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSkiKSArIA0KICAgIHlsYWIoIlJhbmsgYnkgTWV0aG9kIElJIChvcGlvaWQgcHJlc2NyaXB0aW9uIGJ5IHBvcHVsYXRpb24pIikgKyANCiAgICBnZW9tX3RleHRfcmVwZWwoYWVzKGxhYmVsPXN0YXRlX25hbWUpKSAgDQogDQpgYGANCllvdSBjYW4gdGVsbCB0aGF0IHRoZXNlIHR3byBtZXRob2RzIGFyZSBjb25zaXN0ZW50IHdpdGggc29tZSANCmV4Y2VwdGlvbnMuIE9uZSBwb3RlbnRpYWwgcmVhc29uIGlzIHRoYXQgdGhlIHBvcHVsYXRpb24gY29tcG9zaXRpb24gDQppbiBlYWNoIFN0YXRlIGlzIGRpZmZlcmVudCwgbWFraW5nIHRoZSBkaXN0cmlidXRpb25zIG9mIHRvdGFsIA0KcHJlc2NyaXB0aW9ucyBkaWZmZXJlbnQuIFRha2UgU3RhdGUgQSwgd2l0aCBtb3JlIG9sZGVyIHJlc2lkZW50cyAoPj0gODAgeS9vKSwgDQphbmQgU3RhdGUgQiwgd2l0aCBmZXdlciBvbGRlciByZXNpZGVudHMgKD49IDgwIHkvbykuIFRoZW4sIA0KaXQncyB1bmRlcnN0YW5kYWJsZSB0aGF0IHRoZSBhdmVyYWdlIHRvdGFsIHByZXNjcmlwdGlvbnMgcGVyIA0KcGVyc29uIGluIFN0YXRlIEEgbWF5IGJlIGhpZ2hlciB0aGFuIHRoZSBhdmVyYWdlIA0KdG90YWwgcHJlc2NyaXB0aW9ucyBwZXIgcGVyc29uIGluIFN0YXRlIEIuIFRoZXJlIGFyZSBwcm9zIGFuZCBjb25zIA0Kb2YgdGhlc2UgdHdvIGRpZmZlcmVudCBtZXRob2RzLCBhbmQgd2hpY2ggc2hvdWxkIHdlIHVzZSBpcyBoaWdobHkgDQpkZXBlbmRlbnQgb24gdGhlIHF1ZXN0aW9ucyB5b3Ugd2FudCB0byBhZGRyZXNzLiAgIA0KICAgICAgDQpZb3UgbWF5IHdhbnQgdG8gYWxzbyBhZGQgdGhlIGluZm9ybWF0aW9uIGFib3V0IG51bWJlciBvZiBlbnJvbGxtZW50cyBpbiB0aGUgcGxvdC4gSGVyZSwgd2UgcHJvdmlkZSBvbmUgcG90ZW50aWFsIHdheSB0byBkbyBpdCAtIG1ha2luZyB0aGUgc2l6ZSBvZiB0aGUgZG90IHByb3BvcnRpb25hbCB0byB0aGUgbnVtYmVyDQpvZiBlbnJvbGxtZW50LiBUaGlzIGNhbiBiZSBhY2hpZXZlZCBieSBgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IFRIRVZBUklBQkxFWU9VV0FOVFRPUFVUICkpYC4gIA0KDQpgYGB7ciBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD0xMH0NCnAgPC0gbWV0aG9kX2NvbXBhcmlzb24gJT4lIA0KICAgICAgZ2dwbG90KGFlcyh4PXJhbmtfbWV0aG9kMSwNCiAgICAgICAgICAgICAgICAgeSA9IHJhbmtfbWV0aG9kMiwNCiAgICAgICAgICAgICAgICAgY29sb3IgPSByZWdpb24pKSArIA0KICAgICAgZ2VvbV9wb2ludChhZXMoc2l6ZSA9IGVucm9sbG1lbnRfbnVtMjAxNSkpICsgDQogICAgICBnZW9tX2FibGluZShzbG9wZT0xLCBpbnRlcmNlcHQ9MCkNCg0KcCArIHRoZW1lX2J3KCkgKyANCiAgICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICksIA0KICAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgaGp1c3QgPSAxLHZqdXN0ID0gMC41KSkgKyANCiAgICBnZ3RpdGxlKCJDb21wYXJpc29uIG9mIHR3byBtZXRob2RzIHJhbmtpbmcgb3Bpb2lkIHByZXNjcmlwdGlvbiBpbiBNZWRpY2FyZSBQYXJ0IEQgYnkgU3RhdGUgaW4gMjAxNSIsDQogICAgICAgICAgICBzdWJ0aXRsZSA9ICJMb3dlciBudW1iZXIgaW4gcmFuayBtZWFucyBoaWdoZXIgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlLiBcblNpemUgb2YgdGhlIHBvaW50IGlzIHByb3BvcnRpb25hbCB0byB0aGUgbnVtYmVyIG9mIGVucm9sbG1lbnQuIikgKyANCiAgICB4bGFiKCJSYW5rIGJ5IE1ldGhvZCBJIChvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUpIikgKyANCiAgICB5bGFiKCJSYW5rIGJ5IE1ldGhvZCBJSSAob3Bpb2lkIHByZXNjcmlwdGlvbiBieSBwb3B1bGF0aW9uKSIpICsgDQogICAgc2NhbGVfc2l6ZV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hKSArIA0KICAgIGdlb21fdGV4dF9yZXBlbChhZXMobGFiZWw9c3RhdGVfbmFtZSkpICANCmBgYA0KDQogICANCiMjIDUuIExldCdzIHB1dCBpdCBvbiB0aGUgbWFwISAgICANCkluIG1hbnkgY2FzZXMsIHlvdSBtYXkgd2FudCB0byBpbnRlZ3JhdGUgeW91ciBpbmZvcm1hdGlvbiBvbiANCmEgbWFwIHNvIHRoYXQgZG9uJ3QgbmVlZCB0byBtYXAgdGhlIGluZm9ybWF0aW9uIG9uIHRoZSBiYXIgDQpjaGFydCB0byB0aGUgVS5TLiBtYXAgaW4geW91ciBicmFpbi4gSGVyZSwgd2Ugd2lsbCB1c2UgdGhlIA0KYGNob3JvcGxldGhyYCBhbmQgYGNob3JvcGxldGhyTWFwc2AgdG8gaGVscCB1cyBhY2hpZXZlIHRoaXMgDQpnb2FsLiBUaGVyZSBpcyBbYSBuaWNlIHdlYnNpdGVdKGh0dHA6Ly93d3cuYmFyZ2F2YS5jb20vSW50cm8tdG8tQ2hvcm9wbGV0aC11c2luZy1SLykgDQppbnRyb2R1Y2luZyB0aGVzZSBwYWNrYWdlcy4gDQpUaGUgb3RoZXIgY29tbW9uIGFwcHJvYWNoIGlzIHRvIHVzZSBgZ2dtYXBgLCB3aGljaCANCm1heSBhc2sgeW91IHRvIGFwcGx5IGZvciBhIEdvb2dsZSBBUEkga2V5IGluIGFkdmFuY2UuICAgICAgIA0KICAgICAgDQojIyMgU3RlcCAxOiBHZXQgdGhlIGxvY2F0aW9uIGluZm9ybWF0aW9uIGZvciBlYWNoIFN0YXRlICAgIA0KV2UgaGF2ZSBkb25lIHRoaXMgZWFybGllci4gVGhpcyBtZWFucyB0aGF0IHRoZSBkYXRhc2V0IGBzdGF0ZWAgDQpoYXMgYmVlbiBlZGl0ZWQgYnkgdXMuIFRvIHVzZSB0aGUgYGNob3JvcGxldGhyTWFwc2AsIA0Kd2UgbmVlZCB0aGUgb3JpZ2luYWwgYHN0YXRlYCBkYXRhc2V0LCBzbyB3ZSBjYWxsIHRoZSBgbGlicmFyeWAgDQphZ2FpbiwgYW5kIGFzayBmb3IgdGhlIG9yaWdpbmFsIGBzdGF0ZWAgZGF0YXNldC4gDQpgYGB7ciBmaWcud2lkdGg9MTIsZmlnLmhlaWdodD0xMH0NCiMgaHR0cDovL3d3dy5iYXJnYXZhLmNvbS9JbnRyby10by1DaG9yb3BsZXRoLXVzaW5nLVIvDQojIGluc3RhbGwucGFja2FnZXMoImNob3JvcGxldGhyIikNCiMgaW5zdGFsbC5wYWNrYWdlcygiY2hvcm9wbGV0aHJNYXBzIikNCmxpYnJhcnkoZGF0YXNldHMpDQpkYXRhKHN0YXRlKQ0KdW5pcXVlKHN0YXRlLm5hbWUpICMgVGhlcmUgYXJlIG9ubHkgNTAgU3RhdGVzDQpgYGANCiAgICAgDQojIyMgU3RlcCAyOiBQdXQgdGhlIGluZm9ybWF0aW9uIG9uIHRoZSBtYXAgICAgICAgDQpUaGUgZnVuY3Rpb24gd2UgbmVlZCBmb3IgcGxvdCB0aGUgU3RhdGUgbGV2ZWwgbWFwIGlzIA0KYHN0YXRlX2Nob3JvcGxldGhgLCB3aGljaCBuZWVkcyB0aGUgaW5mb3JtYXRpb24gYWJvdXQgDQooMSkgU3RhdGVzJyBsb2NhdGlvbiBpbmZvcm1hdGlvbiwgYW5kICgyKSB2YWx1ZXMsIGFzIGlucHV0LiANClRoZSBgZGZfcG9wX3N0YXRlYCBjb250YWluZWQgaW5mb3JtYXRpb24gYWJvdXQgKDEpIFN0YXRlcycgbG9jYXRpb24gaW5mb3JtYXRpb24sIA0Kc28gYWxsIHdlIG5lZWQgdG8gZG8gaXMgdG8gYWRkIHRoZSBpbmZvcm1hdGlvbiBhYm91dCAoMikgdmFsdWVzLCB3aGljaCANCmlzIHRoZSBvcGlvaWQgUHJlc2NyaXB0aW9uIHBlciAxMDAgZW5yb2xsbWVudHMgYnkgU3RhdGVzLiAgIA0KYGBge3IgZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9MTB9DQpsaWJyYXJ5KGNob3JvcGxldGhyKQ0KbGlicmFyeShjaG9yb3BsZXRock1hcHMpDQoNCnggPC0gcHJlc2NyaWJlcjIwMTVieVN0YXRlICU+JSANCiAgZmlsdGVyKCFpcy5uYShlbnJvbGxtZW50X251bTIwMTUpKSAlPiUNCiAgbXV0YXRlKHJlZ2lvbiA9IHRvbG93ZXIoc3RhdGVfbmFtZSksDQogICAgICAgICB2YWx1ZSA9IG9waW9pZF9jbGFpbV9ieXBvcCkgJT4lICANCiAgZmlsdGVyKCEocmVnaW9uICVpbiUgYygiYW1lcmljYW4gc2Ftb2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJndWFtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAibm9ydGhlcm4gbWFyaWFuYSBpc2xhbmRzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAidmlyZ2luIGlzbGFuZHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJwdWVydG8gcmljbyIpICkgKSAlPiUNCiAgc2VsZWN0KHJlZ2lvbix2YWx1ZSkNCg0KZGF0YSgiZGZfcG9wX3N0YXRlIikNCg0KeSA8LSBkZl9wb3Bfc3RhdGUgJT4lIA0KICByZW5hbWUodmFsdWVvbGQgPSB2YWx1ZSkgJT4lDQogIGxlZnRfam9pbiguLHgsIGJ5ID0gYygicmVnaW9uIikpICU+JSANCiAgc2VsZWN0KHJlZ2lvbix2YWx1ZSkNCg0KcCA8LSBzdGF0ZV9jaG9yb3BsZXRoKHksDQogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kID0gIk9waW9pZCBQcmVzY3JpdGlvbiBDbGFpbXMgXG4gb3Bpb2lkIHBlciAxMDAgZW5yb2xsbWVudHMiLA0KICAgICAgICAgICAgICAgICAgICAgIG51bV9jb2xvcnMgPSA1KQ0KDQpwICsgZ2d0aXRsZSgiT3Bpb2lkIFByZXNjcmlwdGlvbiBwZXIgMTAwIGVucm9sbG1lbnRzIChpbiBNZWRpY2FyZSBQYXJ0IEQpIGJ5IFN0YXRlIGluIDIwMTUiKSArIA0KICB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41ICkpIA0KYGBgDQogICAgICAgDQojIyMgU3RlcCAzOiBQdXQgdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSBpbmZvcm1hdGlvbiBvbiB0aGUgbWFwICAgICAgIA0KV2hhdCB3ZSBuZWVkIHRvIGRvIGlzIHRvIHJlcGxhY2UgdGhlIGluZm9ybWF0aW9uIGFib3V0ICgyKSB2YWx1ZXMsIHdpdGggDQp0aGUgb3Bpb2lkIHByZXNjcmlwdGlvbiByYXRlcyBieSBTdGF0ZXMuICAgICAgICAgIA0KYGBge3IgZmlnLndpZHRoPTEyLGZpZy5oZWlnaHQ9MTB9DQp4IDwtIHByZXNjcmliZXIyMDE1YnlTdGF0ZSAlPiUgDQogIGZpbHRlcighaXMubmEoZW5yb2xsbWVudF9udW0yMDE1KSkgJT4lDQogIG11dGF0ZShyZWdpb24gPSB0b2xvd2VyKHN0YXRlX25hbWUpLA0KICAgICAgICAgdmFsdWUgPSBzdGF0ZV9vcGlvaWRfcHJlc2NyaWJpbmdfcmF0ZSkgJT4lICANCiAgZmlsdGVyKCEocmVnaW9uICVpbiUgYygiYW1lcmljYW4gc2Ftb2EiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJndWFtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAibm9ydGhlcm4gbWFyaWFuYSBpc2xhbmRzIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAidmlyZ2luIGlzbGFuZHMiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICJwdWVydG8gcmljbyIpICkgKSAlPiUNCiAgc2VsZWN0KHJlZ2lvbix2YWx1ZSkNCg0KDQp5IDwtIGRmX3BvcF9zdGF0ZSAlPiUgDQogIHJlbmFtZSh2YWx1ZW9sZCA9IHZhbHVlKSAlPiUNCiAgbGVmdF9qb2luKC4seCwgYnkgPSBjKCJyZWdpb24iKSkgJT4lIA0KICBzZWxlY3QocmVnaW9uLHZhbHVlKQ0KDQpwIDwtIHN0YXRlX2Nob3JvcGxldGgoeSwNCiAgICAgICAgICAgICAgICAgICAgICBsZWdlbmQgPSAiT3Bpb2lkIFByZXNjcml0aW9uIFJhdGUgXG4gb3Bpb2lkIGNsYWltcyBwZXIgMTAwIHRvdGFsIGNsYWltcyIsDQogICAgICAgICAgICAgICAgICAgICAgbnVtX2NvbG9ycyA9IDUpDQoNCnAgKyBnZ3RpdGxlKCJPcGlvaWQgUHJlc2NyaXB0aW9uIFJhdGUgKGluIE1lZGljYXJlIFBhcnQgRCkgYnkgU3RhdGUgaW4gMjAxNSIpICsgDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUgKSkgDQpgYGANCiAgICAgDQojIFN1bW1hcnkgICANCkNhbGlmb3JuaWEsIEZsb3JpZGEsIFRleGFzLCBQZW5uc3lsdmFuaWEsIGFuZCBNaWNoaWdhbiBhcmUgdGhlIHRvcCBmaXZlIFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IG9waW9pZCBwcmVzY3JpcHRpb24gY2xhaW1zIGluIFBhcnQgRCBpbiAyMDE2LiBIb3dldmVyLCBhZnRlciB0YWtpbmcgdGhlIHBvcHVsYXRpb24gb2YgdGhlIFN0YXRlcyBpbnRvIGFjY291bnQsIHRoZXkgd2VyZSBub3QgdGhlIHRvcCBmaXZlIFN0YXRlcyB3aXRoIHRoZSBoaWdoZXN0IG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZXMuIEluc3RlYWQsIE5ldmFkYSwgVXRhaCwgQWxhYmFtYSwgT2tsYWhvbWEsIElkYWhvIGhhZCB0aGUgaGlnaGVzdCBvcGlvaWQgcHJlc2NyaXB0aW9uIGNsYWltcyBwZXIgMTAwIGVucm9sbG1lbnRzLiBJbiBnZW5lcmFsLCB0aGUgdHJlbmQgdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSB3YXMgZGVjcmVhc2luZyBkdXJpbmcgMjAxMyAtIDIwMTYgYWNyb3NzIG1vc3Qgb2YgdGhlIFN0YXRlcy4gSG93ZXZlciwgdGhlIGRhdGEgZm9yIA0KdGhpcyBhbmFseXNpcyBjYW1lIGZyb20gTWVkaWNhcmUgUGFydCBELCBhbmQgdGh1cyBvcGlvaWQgcHJlc2NyaXB0aW9uIGluZm9ybWF0aW9uIGZvciByZWxhdGl2ZWx5IHlvdW5nZXIgYWR1bHRzIHdhcyBtaXNzaW5nIGluIHRoZSBhbmFseXNpcy4gQ29tYmluaW5nIA0KdGhlc2UgZGF0YSB3aXRoIG9waW9pZC1yZWxhdGVkIHBvbGljaWVzIGFjcm9zcyBTdGF0ZXMgbWF5IGJlIG1vcmUgaW5mb3JtYXRpdmUuIA0KDQogICAgICAgICAgIA0KIyBBcHBlbmRpeCAgICAgICAgICANClRoZXJlIGFyZSBhdCBsZWFzdCB0d28gZXh0ZW50aW9ucyB5b3UgY2FuIG1ha2UgZnJvbSB0aGlzIGNhc2Ugc3R1ZHkuICAgIA0KVGhlIGZpcnN0IG9uZSBpcyBsaW5raW5nIHRoaXMgd2l0aCBtb3JlIHB1YmxpY2x5IGF2YWlsYWJsZSBkYXRhLiANClRoZSBzZWNvbmQgb25lIGlzIHRvIGRlbW9uc3RyYXRlIGxvbmdpdHVkaW5hbCBkYXRhIGFuYWx5c2lzLiAgICAgDQogICAgIA0KIyMgRXh0ZW5zaW9uIDEgOiBBZGRpdGlvbmFsIGRhdGEgc291cmNlICAgICAgICANCmBNZWRpY2FyZSBQYXJ0IEQgYmVuZWZpY2lhcmllcyBpbmZvcm1hdGlvbmAgaXMgcHVibGljbHkgYXZhaWxhYmxlLCBhbmQgDQptYXkgcHJvdmlkZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIHlvdSBhcmUgaW50ZXJlc3RlZCBpbi4gDQpUaGUgaW5mb3JtYXRpb24gYWJvdXQgTWVkaWNhcmUgUGFydCBEIGJlbmVmaWNpYXJpZXMgYXJlIHB1YmxpY2x5IGF2YWlsYWJsZS4gSGVyZSwgd2UgDQpkZW1vbnN0cmF0ZSBob3cgdG8gZG93bmxvYWQgZmlsZSBmcm9tIHRoZSB3ZWJzaXRlIGRpcmVjdGx5IHVzaW5nIHRoZSBtZXRob2QgYXMgDQp0aGUgYWZvcmVtZW50aW9uZWQuIEhvd2V2ZXIsIHRoaXMgaXMgb25seSBmb3IgZGVtb25zdHJhdGlvbiBwdXJwb3NlLCBhbmQgDQpub3QgZ29pbmcgdG8gYmUgdXNlZCBpbiB0aGlzIHByb2plY3QuIA0KYGBge3IgZXZhbD1GQUxTRX0NCmlmKCFmaWxlLmV4aXN0cygiLi9kYXRhLzIwMTZwYXJ0RHByZXNjcmliZXJpbmZvLmNzdiIpKXsNCiAgZmlsZV9saW5rIDwtICJodHRwczovL2RhdGEuY21zLmdvdi9hcGkvdmlld3MveXZwai1wbWoyL3Jvd3MuY3N2Ig0KICBkb3dubG9hZC5maWxlKGZpbGVfbGluaywNCiAgICAgICAgICAgICAgICBkZXN0ZmlsZSA9ICIuL2RhdGEvMjAxNnBhcnREcHJlc2NyaWJlcmluZm8uY3N2Iixtb2RlID0gIndiIikgDQogIH0NCg0KaWYoIWZpbGUuZXhpc3RzKCIuL2RhdGEvMjAxNXBhcnREcHJlc2NyaWJlcmluZm8uY3N2Iikpew0KICBmaWxlX2xpbmsgPC0gImh0dHBzOi8vZGF0YS5jbXMuZ292L2FwaS92aWV3cy8zejRkLXZtaG0vcm93cy5jc3YiDQogIGRvd25sb2FkLmZpbGUoZmlsZV9saW5rLA0KICAgICAgICAgICAgICAgIGRlc3RmaWxlID0gIi4vZGF0YS8yMDE1cGFydERwcmVzY3JpYmVyaW5mby5jc3YiLG1vZGUgPSAid2IiKSANCiAgfQ0KDQppZighZmlsZS5leGlzdHMoIi4vZGF0YS8yMDE0cGFydERwcmVzY3JpYmVyaW5mby5jc3YiKSl7DQogIGZpbGVfbGluayA8LSAiaHR0cHM6Ly9kYXRhLmNtcy5nb3YvYXBpL3ZpZXdzLzQ2NWMtNDlwYi9yb3dzLmNzdiINCiAgZG93bmxvYWQuZmlsZShmaWxlX2xpbmssDQogICAgICAgICAgICAgICAgZGVzdGZpbGUgPSAiLi9kYXRhLzIwMTRwYXJ0RHByZXNjcmliZXJpbmZvLmNzdiIsbW9kZSA9ICJ3YiIpIA0KICB9DQoNCg0KaWYoIWZpbGUuZXhpc3RzKCIuL2RhdGEvMjAxM3BhcnREcHJlc2NyaWJlcmluZm8uY3N2Iikpew0KICBmaWxlX2xpbmsgPC0gImh0dHBzOi8vZGF0YS5jbXMuZ292L2FwaS92aWV3cy80dXZjLWdiZnovcm93cy5jc3YiDQogIGRvd25sb2FkLmZpbGUoZmlsZV9saW5rLA0KICAgICAgICAgICAgICAgIGRlc3RmaWxlID0gIi4vZGF0YS8yMDEzcGFydERwcmVzY3JpYmVyaW5mby5jc3YiLG1vZGUgPSAid2IiKSANCiAgfQ0KDQpgYGANClRoZSBmb2xsb3dpbmcgaXMgdGhlIGNvZGUgYm9vay4gSW4gb3RoZXIgd29yZHMsIA0KdGhlIGRlc2NyaXB0aW9uIG9mIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgDQp3ZSBqdXN0IGRvd25sb2FkZWQgaXMgc3VtbWFyaXplZCBpbiB0aGUgZm9sbG93aW5nIA0KdGFibGU6IChPZiBub3RlLCBOUEkgc3RhbmRzIGZvciBOYXRpb25hbCBQcm92aWRlciBJZGVudGlmaWVyLCANCmFuZCBOUFBFUyBzdGFuZHMgZm9yIENNUyBOYXRpb25hbCBQbGFuIGFuZCBQcm92aWRlciBFbnVtZXJhdGlvbiBTeXN0ZW0uIA0KSW4gZ2VuZXJhbCwgaGVhbHRoY2FyZSBwcm92aWRlcnMgaGF2ZSB0aGVpciB1bmlxdWUgDQoxMC1kaWdpdCBOUElzIHRvIGlkZW50aWZ5IHRoZW1zZWx2ZXMsIGFuZCBtb3JlIGluZm9ybWF0aW9uIGNhbiBiZSBmb3VuZCANCmluIHRoZSBbTlBJIFJlZ2lzdHJ5IFB1YmxpYyBTZWFyY2hdKGh0dHBzOi8vbnBpcmVnaXN0cnkuY21zLmhocy5nb3YvKSkNCmBgYHtyfQ0KcGFydGRpbmZvZGVzY3JpcHRpb24gPSByZWFkLmNzdigiLi9kb2MyL3BhcnRkaW5mb2Rlc2NyaXB0aW9uLmNzdiIpIA0KbmFtZXMocGFydGRpbmZvZGVzY3JpcHRpb24pWzFdIDwtICJDb2x1bW4gTmFtZSINCnBhcnRkaW5mb2Rlc2NyaXB0aW9uICU+JQ0KICBzZWxlY3QoYENvbHVtbiBOYW1lYCxEZXNjcmlwdGlvbikgJT4lDQogIGthYmxlKCkgJT4lDQogIGthYmxlX3N0eWxpbmcoKSAlPiUNCiAgY29sdW1uX3NwZWMoMSwgYm9sZCA9IFQsIGJvcmRlcl9yaWdodCA9IFQsIGJhY2tncm91bmQgPSAid2hpdGUiKSAlPiUNCiAgY29sdW1uX3NwZWMoMiwgd2lkdGggPSAiMzBlbSIsIGJhY2tncm91bmQgPSAibGlnaHR5ZWxsb3ciKQ0KYGBgICAgIA0KICAgICAgICAgICAgICAgDQojIyBFeHRlbnNpb24gMiA6IExvbmdpdHVkaW5hbCBkYXRhIGFuYWx5c2lzICAgICAgDQogVGhlIGFib3ZlIHBsb3RzIHNob3dpbmcgdGhlIGxvbmdpdHVkaW5hbCB0cmVuZCANCm1heSBpbnNwaXJlIHlvdSB0aGUgZm9sbG93aW5nIHF1ZXN0aW9uczogICAgDQogICAgIA0KKDEpIElzIHRoZSByZWdpb24gYXNzb2NpYXRlZCB3aXRoIHRoZSBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgDQphdCB0aGUgYmFzZWxpbmUgKGFrYSwgYXQgeWVhciAyMDEzKT8gICAgICAgIA0KICAgICANCigyKSBJcyB0aGUgcmVnaW9uIGFzc29jaWF0ZWQgd2l0aCB0aGUgcmF0ZSBvZiBkZWNsaW5lIGluIG9waW9pZCANCnByZXNjcmlwdGlvbiByYXRlIGFjcm9zcyB0aW1lIGR1cmluZyAyMDEzIC0gMjAxNj8gICAgIA0KICAgICAgICANClRoZXNlIGFyZSBhbGwgZ3JlYXQgcXVlc3Rpb25zLCBidXQgd2UgYXJlIG5vdCBnb2luZyB0byBkaXNjdXNzIA0KYWJvdXQgdGhpcyBkZWVwbHkgaW4gdGhpcyBjYXNlIHN0dWR5LiBJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gDQp0aGVzZSBxdWVzdGlvbnMsIHdlIHdvdWxkIHJlY29tbWVuZCB5b3UgdG8gcmVhZCBzb21lIG1hdGVyaWFscyANCmFib3V0IGxvbmdpdHVkaW5hbCBkYXRhIGFuYWx5c2lzLiBGb3IgeW91ciBjb252ZW5pZW5jZSwgd2UgDQpkbyBwcm92aWRlIHNvbWUgc2FtcGxlIGNvZGVzLiBXZSB3aWxsIHJ1biB0d28gbGluZWFyIG1peGVkIGVmZmVjdCANCm1vZGVscyB1c2luZyB0aGUgcGFja2FnZSBgbG1lNGAsIGFuZCBwcm92aWRlIGJyaWVmIGludGVycHJldGF0aW9uLiANCkluIHRoZSBmaXJzdCBtb2RlbCBgZml0MWAsIHdlIGFyZSBpbnZlc3RpZ2F0aW5nIHdoZXRoZXIgDQp0aGUgcmVnaW9uIGlzIGFzc29jaWF0ZWQgd2l0aA0KdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSBpbiB0aGUgeWVhciAyMDEzIHdoaWxlIHdlIGRvbid0IGFsbG93IA0KdGhlIGNoYW5nZSBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgdG8gYmUgZGlmZmVyZWQgYnkgcmVnaW9uLiANCkluIHRoZSBzZWNvbmQgbW9kZWwgYGZpdDJgLCB3ZSBhcmUgaW52ZXN0aWdhdGluZyB3aGV0aGVyIHRoZSByZWdpb24gDQppcyBhc3NvY2lhdGVkIHdpdGggdGhlIG9waW9pZCBwcmVzY3JpcHRpb24gcmF0ZSBpbiB0aGUgeWVhciAyMDEzIGFuZCANCndoZXRoZXIgcmVnaW9uIGFzc29jaWF0ZWQgd2l0aCB0aGUgcmF0ZSBvZiBkZWNsaW5lIGluIG9waW9pZCANCnByZXNjcmlwdGlvbiByYXRlIGFjcm9zcyB0aW1lIGR1cmluZyAyMDEzIC0gMjAxNiBhdCB0aGUgc2FtZSB0aW1lIA0Kd2hpbGUgd2UgYWxsb3cgdGhlIGNoYW5nZSBvZiBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgdG8gYmUgZGlmZmVyZWQgDQpieSByZWdpb25zLiAgICANCioqKCBOb3RlOiBUaGUgaW5zdHJ1Y3RvcnMgc3RpbGwgbmVlZCB0byBhZGQgdGhlIGludGVycHJldGF0aW9uIG9mIHJhbmRvbSBpbnRlcmNlcHQgYW5kIHJhbmRvbSBzbG9wZS4pKioNCmBgYHtyfQ0KbGlicmFyeShsbWU0KQ0KDQpmaXQxIDwtIGxtZXIoc3RhdGVfb3Bpb2lkX3ByZXNjcmliaW5nX3JhdGUgfiBhcy5mYWN0b3IocmVnaW9uKSArIGludGVydmFsICsgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKDEgfCBzdGF0ZV9uYW1lKSwgDQogICAgICAgICAgICAgZGF0YSA9ICBkYXRhbW9kZWwpDQoNCnN1bW1hcnkoZml0MSkNCg0KZml0MiA8LSBsbWVyKHN0YXRlX29waW9pZF9wcmVzY3JpYmluZ19yYXRlIH4gYXMuZmFjdG9yKHJlZ2lvbikqaW50ZXJ2YWwgKyBpbnRlcnZhbCArIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgxICsgaW50ZXJ2YWwgfCBzdGF0ZV9uYW1lKSwgDQogICAgICAgICAgICAgZGF0YSA9ICBkYXRhbW9kZWwpDQoNCnN1bW1hcnkoZml0MikNCmBgYA0KRnJvbSB0aGVzZSBtb2RlbHMsIHdlIGNhbiBjb25jbHVkZSB0aGF0IHRoZSBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgDQp3YXMgZGVjcmVhc2luZyBvdmVyIHRpbWUgZHVyaW5nIDIwMTMgLSAyMDE2LiBUaG91Z2ggdGhlcmUgYXJlIHNvbWUgDQpkaWZmZXJlbmNlIGluIHRoZSBvcGlvaWQgcHJlc2NyaXB0aW9uIHJhdGUgYWNyb3NzIGRpZmZlcmVudCByZWdpb25zIA0KYXQgdGhlIGJhc2VsaW5lIChpbiB0aGUgeWVhciAyMDEzKSwgdGhlcmUgaXMgbm8gb2J2aW91cyBkaWZmZXJlbmNlIGluIA0KdGhlIHRyZW5kIG9mIGRlY2xpbmUgYWNyb3NzIGRpZmZlcmVudCByZWdpb25zLiAgIA0KDQo=